/* BOMBER INSTINCT */ /* Copyright © 2000 by Louis Gesbert and TeraSoft */ /* * 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. */ /* * Contact me at : metagribouille@netcourrier.com. * * +----------------------+ * Web site : |www.bomberinstinct.org| * +----------------------+ */ #include #include #include #include #include #include #include #include "main.h" #include "pouvoirs.h" #include "niveaux.h" #include "evenements.h" #include "options.h" #include "son.h" #include "gamelogic.h" #include "intro.h" /***********************************/ /*-----D é c l a r a t i o n s-----*/ /***********************************/ /*--Variables globales de configuration--*/ /* des options */ Uint32 flags=SDL_HWSURFACE|SDL_HWPALETTE; /* des fichiers */ char repertoire[256]; char prefixeniv[256], prefixeimg[256]; char prefixespr[256], prefixeson[256]; /*--Structures qui servent en continu dans le jeu--*/ Plateau pl[16][15]; /* Toutes les cases qui constituent le niveau */ Personnage perso[8]; /* Description de l'état des personnages */ int nperso=2; /* réglage du nb de joueurs ds le menu */ Coord rscase[2][260]; int nrscase[2]={0,0}; /* Les cases à redessiner */ Coord rstunnel[2][260]; int ntunnel[2]={0,0}; /* pareil, mais par-dessus le reste */ SDL_Rect rsrect[512]; int nrsrect=0; /* Parties de l'écran à mettre à jour */ int nrs=0; /* sur quel buffer est le double-buffering */ Anims * anims=NULL; /* Animations à l'écran */ Anims * animsfin=NULL; /* On garde un pointeur sur le dernier élément pour que les animations plus récentes passent par-dessus */ /*--Trucs dont le programme a besoin de se souvenir--*/ char **spritliste; SDL_Surface * bande; SDL_Surface * fondecran; SDL_Surface * txtmodesjeu[NMODES]; int score[8]; int enpause=0; /*--Entrées/Sorties--*/ SDL_Surface *ecran; Uint8 *clavier; SDL_Joystick **joystick; int numjoys; /*--Variables qui servent en cours de jeu--*/ int compteur; int encore; /*--Variables des autres trucs dont on doit se souvenir quelque temps--*/ int danslemenu; int options; int choisi=0; Coord fauxperso[MAX_NPERSO]; const int dx[4]={ 0, 0,-1, 1}; /* Donne le déplacement en x à partir de la direction */ const int dy[4]={-1, 1, 0, 0}; /* Donne le déplacement en y à partir de la direction */ /********************************/ /*-------F o n c t i o n s------*/ /********************************/ /*--Initialiser SDL--*/ int init_sdl(void) { Uint32 params; SDL_Surface *icone; char chemin[256], titre[256]; int ok; params = avecson ? SDL_INIT_VIDEO|SDL_INIT_AUDIO : SDL_INIT_VIDEO; if (avecjoy) params |= SDL_INIT_JOYSTICK; if ( SDL_Init(params) < 0 ) { printf("Impossible d'initialiser SDL: %s\n",SDL_GetError()); exit(1); } if (avecjoy) { numjoys=SDL_NumJoysticks(); printf("%i joysticks détectés: support %s.\n", numjoys, numjoys>0 ? "activé" : "désactivé"); } else { numjoys=0; printf("Support du joystick désactivé.\n"); } sprintf(titre, "Bomber Instinct - v%s", VERSION); SDL_WM_SetCaption(titre, "BomberInstinct"); sprintf(chemin, "%s/icone.bmp", prefixeimg); icone=SDL_LoadBMP(chemin); SDL_SetColorKey(icone, SDL_SRCCOLORKEY, 0); SDL_WM_SetIcon(icone, NULL); SDL_FreeSurface(icone); if (dblebuf) flags |= SDL_DOUBLEBUF; params = pleinecran ? flags|SDL_FULLSCREEN : flags; ok=SDL_VideoModeOK(640, 480, 8, params); if (!ok) erreur("Le mode vidéo requis n'est pas disponible (640x480)", NULL); #ifdef DEBUG else if (ok!=8) { printf("Impossible de passer en mode couleurs 8 bits.\n"); printf("Le jeu tournera, mais en émulation donc plus lentement.\n"); } #endif ecran = SDL_SetVideoMode(640, 480, 8, params); if ( ecran == NULL ) { printf("Impossible de choisir le mode 640*480 8 bits!\n%s\n", SDL_GetError()); return 1; } if ((ecran->flags & SDL_DOUBLEBUF)==SDL_DOUBLEBUF) { dblebuf=1; printf("Double buffering: activé.\n"); } else if (dblebuf<2) { dblebuf=0; printf("Double buffering: désactivé.\n"); } else dblebuf=1; atexit(SDL_Quit); atexit(SDL_CloseAudio); SDL_EventState(SDL_APPMOUSEFOCUS|SDL_MOUSEBUTTONDOWN|SDL_MOUSEBUTTONUP| SDL_MOUSEMOTION|SDL_SYSWMEVENT, SDL_IGNORE); SDL_EnableKeyRepeat(0,0); SDL_ShowCursor(0); return 0; } /*--Initialisation des joysticks--*/ void initjoy(void) { int i; joystick=(SDL_Joystick **)calloc(sizeof(SDL_Joystick *), numjoys); for (i=0; iflags & SDL_DOUBLEBUF)==SDL_DOUBLEBUF) dblebuf=1; else dblebuf=0; return; } /*--Attend que le délai de boucle principale soit au moins VITESSE pour repartir--*/ int ajustevitesse(void) { static int repart=0; int t; #ifdef DEBUG int ecoule=repart ? SDL_GetTicks()-repart+VITESSE : VITESSE-1; #endif do t=SDL_GetTicks(); while (tformat->palette->ncolors, 10); SDL_PauseAudio(1); do SDL_WaitEvent(&evt); while (evt.type!=SDL_KEYDOWN || !(SDL_GetAppState()&SDL_APPACTIVE)); restorepalette(pal, 50); SDL_PauseAudio(0); enpause=0; return; } /*--Affiche des informations, pose une question--*/ void dialogue(char * texte, int estunequestion) { int nlignes=0; const char delim[]="#"; SDL_Event evt; paletsg pal; char * lignes[256]; SDL_Surface *surf; surf=SDL_CreateRGBSurface (0, 640, 480, 16, 0,0,0,0); while (SDL_PollEvent(&evt)); /* Vider la file d'évènements */ pal=changepalette(0.8, 0.8, 0.8, 0, 0, 1, ecran->format->palette->ncolors, 10); // while (lignes[nlignes]=strtok(texte, &delim)) nlignes++; XCenteredString(surf, 100,"Bonjour\nComment ça va ?"); SDL_BlitSurface(surf, NULL, ecran, NULL); rafraichit(); do SDL_WaitEvent(&evt); while (evt.type!=SDL_KEYDOWN || !(SDL_GetAppState()&SDL_APPACTIVE)); restorepalette(pal, 50); SDL_PauseAudio(0); enpause=0; return; } /*--Met en place des raccourcis-clavier--*/ int filtr_evt(const SDL_Event *evt) { if (evt->type == SDL_QUIT) exit(0); if (evt->type == SDL_KEYDOWN) { if (evt->key.keysym.sym==SDLK_F10) exit(0); if (evt->key.keysym.sym==SDLK_F1) passenpleinecran(); if (evt->key.keysym.sym==SDLK_PAUSE) enpause=1; } if (evt->type == SDL_ACTIVEEVENT) if (evt->active.type==SDL_APPACTIVE && !evt->active.gain) enpause=1; return 1; } /*--Affiche un écran noir--*/ void videcran(void) { SDL_Rect tout={0, 0, 640, 480}; SDL_FillRect(ecran, &tout, 0); SDL_Flip(ecran); if (dblebuf) { SDL_FillRect(ecran, &tout, 0); SDL_Flip(ecran); } return; } /*--Remet les structures utilisées pendant le jeu à zéro--*/ void reinit(void) { int i; Anims * a; Evenement * e; while (anims) { a=anims->suiv; free(anims); anims=a; } while (evts[AVANT]) { e=evts[AVANT]->suiv; free(evts[AVANT]); evts[AVANT]=e; } while (evts[APRES]) { e=evts[APRES]->suiv; free(evts[APRES]); evts[APRES]=e; } for (i=0; isuiv; free(perso[i].bombes); perso[i].bombes=pt; } } danslemenu=0; compteur=0; encore=1; nrsrect=0; nrscase[0]=0; nrscase[1]=0; nrs=0; ntunnel[0]=0; ntunnel[1]=0; decl=0; return; } /*--Règle les joysticks pour les joueurs--*/ void initjoy_persos() { int i; for (i=0; i<8; i++) { perso[i].cmd.joy=NULL; if (perso[i].cmd.bas==0 || perso[i].cmd.gauche==0 || perso[i].cmd.droite==0 || perso[i].cmd.b1==0 || perso[i].cmd.b2==0) { int njoy=perso[i].cmd.haut; if (njoy>=numjoys || joystick[njoy]==NULL) printf("Attention : Impossible d'initialiser le joystick %i demandé.\n", njoy); else perso[i].cmd.joy=joystick[njoy]; } } return; } /*--Initialise la structure perso avant chaque partie--*/ void initperso(int n) { perso[n].dir=BAS; perso[n].anim=BAS; perso[n].mv=0; perso[n].statut=VIVANT; perso[n].animdroite=REPOS; perso[n].energie=100; perso[n].lflammes=2; perso[n].bombes=NULL; perso[n].pos.x=perso[n].pos.y=0; if (spritliste[n]) initpouv(n); return; } /*--Ajoute un rectangle à rafraichir--*/ void rsrectplus(int x, int y, int w, int h) { rsrect[nrsrect].x=x; rsrect[nrsrect].y=y; rsrect[nrsrect].w=w; rsrect[nrsrect].h=h; nrsrect++; return; } /*--Ajoute une case du plateau à redessiner--*/ void rscaseplus(int x, int y) { int i; if (pl[x][y].type==TUNNEL) { /* On vérifie que la case n'est pas déjà présente car * le blit est le truc le plus lent. */ for (i=0; iprec=nouv; else animsfin = nouv; nouv->suiv=anims; nouv->prec=NULL; nouv->pos.x=x; nouv->pos.y=y; nouv->anim=anim; nouv->frame=0; nouv->vitesse=vitesse; nouv->duree=duree; nouv->sprite=sprite; if (vitesse) nouv->compteur=0; else nouv->compteur=1; anims=nouv; return nouv; } /*--Supprime l'animation a (a!=NULL)--*/ void animsmoins(Anims * a) { if (a==NULL) erreur("Erreur interne 4654132 : veuillez contacter le programmeur", NULL); rscaseplus(a->pos.x, a->pos.y); if (a->suiv) a->suiv->prec=a->prec; if (a->prec) a->prec->suiv=a->suiv; else { if (a->suiv==NULL) animsfin=NULL; anims = a->suiv; } /* a est le premier élément de anims. anims doit maintenant pointer sur le suivant */ free(a); return; } /*--Redessine une case (x, y) du plateau--*/ void dessinecase(int ncases, Coord *co) { int i; for (i=0; i non libre */ /* 1 -> libre */ /* -1 -> non libre mais destructible */ /* -2 -> non libre à cause d'une bombe */ int libre(int x, int y, int dir) { int ret=0; if (x<0 || 15=NBOMBES) || (pl[x][y].bombe)) // && libre(x, y, 4)>0 return NULL; perso[n].energie-=NBOMBES; nouv=(Bombe *)malloc(sizeof(Bombe)); if (perso[n].bombes) perso[n].bombes->prec=nouv; nouv->suiv=perso[n].bombes; nouv->prec=NULL; nouv->pos.x = x; nouv->pos.y = y; if (perso[n].statut & ETEINT) nouv->rebours = -1; else nouv->rebours = REBOURS; nouv->lflammes = perso[n].lflammes; nouv->car=0; if (perso[n].statut & DETONATEUR) { nouv->rebours = -1; } if (perso[n].statut & SUPERBOMBE) { nouv->car=SUPERBOMBE; perso[n].pouvactif[0]+=ACTIVATION; } perso[n].bombes=nouv; pl[x][y].bombe = BOMBE; return nouv; } /*--Supprime l'animation d'un bonus--*/ void bonusmoins(int x, int y) { Anims * pt=anims; while (pt) { if (pt->sprite==bonus && pt->pos.x==x && pt->pos.y==y) { animsmoins(pt); break; } pt=pt->suiv; } //animsplus destruction du bonus... return; } /*--Ramassage d'un bonus par un joueur--*/ void prendbonus(int n) { int x, y; x=perso[n].pos.x; y=perso[n].pos.y; bruitsplus(s_bonus, 1); switch(pl[x][y].params[0]) { case FLAMMESB: { perso[n].lflammes++; }break; case ENERGIEB: { perso[n].energie += (50+aleat(40)); if (perso[n].energie>255) perso[n].energie=255; }break; case POUVOIRB: { pouvoirplus(n, 0, 0); }break; } pl[x][y].type=LIBRE; bonusmoins(x,y); return; } /*--Affichage d'un joueur à l'écran--*/ void afficheperso(int n, int frame) { if (perso[n].statut&INVISIBLE) return; else if (perso[n].statut&DEGUISE) blitsprit(mur,2,0,perso[n].pixpos.x, perso[n].pixpos.y); else if (sprit[n]->anims[0]->nframes<8) /* Autrement dit, le personnage est une citrouille */ blitsprit(sprit[n], 0, (compteur/2)%sprit[n]->anims[0]->nframes, perso[n].pixpos.x,perso[n].pixpos.y); else blitsprit(sprit[n],perso[n].anim,frame,perso[n].pixpos.x,perso[n].pixpos.y); return; } /*--Anime les mouvements des joueurs--*/ void animouv(int n) { int dirx, diry; int mv, frame=0; int x, y; x=perso[n].pos.x; y=perso[n].pos.y; perso[n].pixpos.x = x*32; perso[n].pixpos.y = y*32; dirx=dx[perso[n].dir]; diry=dy[perso[n].dir]; mv=perso[n].mv; //if (perso[n].action!=RIEN || perso[n].action==INVINCIBLE) perso[n].anim=perso[n].dir; /* Si le personnage est déguisé, pour lui les propriétés */ /* de sa case restent les mêmes même si elles changent pour */ /* les autres. */ if (perso[n].statut & DEGUISE) { pl[x][y].type=perso[n].pouvoirparam; } rscaseplus(x, y); if (mv>0) { perso[n].pixpos.x+=4*mv*dirx; perso[n].pixpos.y+=4*mv*diry; rscaseplus(x+dirx, y+diry); frame=mv; } if (mv==-1 || (perso[n].statut&RAPIDE && mv==-2) ) { if (pl[x][y].type==EVENEMENT) evtsplus(pl[x][y].evt, n, x, y, 0, 1, pl[x][y].nparams ? pl[x][y].params[0] : 0, APRES, NULL); if (pl[x][y].type==BONUS) prendbonus(n); } if (mv<0) { mv++; /* mv est artificiellement minoré de 1 pour distinguer */ /* quand le personnage arrive sur une case ou s'il y est déjà */ perso[n].pixpos.x+=4*mv*dirx; perso[n].pixpos.y+=4*mv*diry; if (mv) { rscaseplus(x-dirx, y-diry); frame=8+mv; } /* (mv<=0) */ else frame=0; } afficheperso(n, frame); /* Le personnage est déguisé, les autres le prennent donc pour un mur */ if (perso[n].statut & DEGUISE) { perso[n].pouvoirparam=pl[x][y].type; pl[x][y].type=CAMOUFL; } if (perso[n].mv) { perso[n].mv++; } /* Les 4 premières frames de mouvement sont positives (1..4) */ /* et les 4 dernières négatives (-5..-1 -> -4..-0) */ /* Comme ça le personnage est considéré comme étant sur la case */ /* dont il est le plus proche. */ if (perso[n].mv==4) { if (perso[n].statut & DEGUISE) { pl[x][y].type=perso[n].pouvoirparam; perso[n].pouvoirparam=pl[x+dirx][y+diry].type; pl[x+dirx][y+diry].type=CAMOUFL; } perso[n].pos.y+=diry; perso[n].pos.x+=dirx; perso[n].mv=-5; } if (perso[n].mv && perso[n].statut&RAPIDE) perso[n].mv++; return; } /*--Tentative d'assassinat du personnage "tue" par une bombe de "tueur"--*/ void mort(int tueur, int tue) { int i, n_en_vie=0; if (perso[tue].statut&INVINCIBLE || !(perso[tue].statut&VIVANT)) return; if (perso[tue].statut&DEGUISE) pl[perso[tue].pos.x][perso[tue].pos.y].type=perso[tue].pouvoirparam; if (modejeu==MODE_DEATHMATCH_GORE || (modejeu==MODE_DEATHMATCH && tueur!=tue)) score[tueur]++; perso[tue].statut=MORT; perso[tue].animdroite=AGONIE; if (sprit[tue]->nanims>7) animsplus(sprit[tue], ANIM_MORT, 4, 1, perso[tue].pos.x, perso[tue].pos.y); bruitsplus(s_mort, 1); for (i=0; ipos.x][b->pos.y].bombe = EXPL; evtsplus(destruction, n, b->pos.x, b->pos.y, 0, 1, 0, AVANT, NULL); bruitsplus(s_expl, 1); if (b->suiv) b->suiv->prec=b->prec; if (b->prec) b->prec->suiv=b->suiv; else /* b est la première bombe, "bombes" pointe maintenant sur b->suiv */ perso[n].bombes = b->suiv; tue(b->pos.x, b->pos.y, n); propagflam(n, b->pos.x, b->pos.y, b->lflammes, b->car==SUPERBOMBE); free(b); return; } /*--Détecte la bombe de la case (x,y) pour la faire exploser--*/ void explosebombe (int x, int y) { int i; Bombe * pt; for (i=0; ipos.x==x && pt->pos.y==y) { pt->rebours=1; return; } pt=pt->suiv; } } return; /* Ne devrait servir à rien */ } /*--Casse un mur destructible--*/ void detruitbloc(int x, int y) { int param; pl[x][y].elem = sol; pl[x][y].anim = 0; pl[x][y].frame = 0; pl[x][y].type = LIBRE; pl[x][y].bombe = EXPL; evtsplus(destruction, 0, x, y, 0, 1, 0, AVANT, NULL); animsplus(bloc, 1, 2, 1, x, y); if (aleat(BONUSFREQ)==0) { param=aleat(10); pl[x][y].params=(int *)malloc(sizeof(int)); pl[x][y].nparams=1; if (0<=param && param<5) pl[x][y].params[0]=FLAMMESB; else if (5<=param && param<9) pl[x][y].params[0]=ENERGIEB; else if (9<=param && param<10) pl[x][y].params[0]=POUVOIRB; pl[x][y].type=BONUS; animsplus(bonus, pl[x][y].params[0], 2, 0, x, y); } return; } /*--Propagation des flammes des bombes--*/ void propagflam(int n, int ox, int oy, int lflammes, int sup) { int i, j; int x, y; int type; int anim; int caselibre; for (i=0; i<4; i++) { for (j=1; j<=lflammes; j++) { x=ox+dx[i]*j; y=oy+dy[i]*j; if (x<0 || x>15 || y<0 || y>14) break; if (!partir(x, y, i)) break; caselibre=libre(x, y, i); type=pl[x][y].type; /* Contrairement aux personnages, * les flammes font peu de cas du déguisement */ if (pl[x][y].type==CAMOUFL) caselibre=1; if (caselibre==-2) { /* S'il y a une bombe mais que ç'aurait été libre sinon */ tue(x, y, n); explosebombe(x,y); if (!sup) break; } else if (!caselibre && pl[x][y].type==TUNNEL) /* Il y a un tunnel qui empêche le passage de la flamme */ break; else if (pl[x][y].bombe==EXPL) { /* L'élément a été détruit à ce round */ tue(x, y, n); if (!sup) break; } else if (type==BONUS) { tue(x, y, n); pl[x][y].type=LIBRE; pl[x][y].bombe=EXPL; evtsplus(destruction, n, x, y, 0, 1, 0, AVANT, NULL); bonusmoins(x,y); if (!sup) break; /* Les super-flammes continuent leur chemin */ else { anim = (j==lflammes) ? (i+3) : (i/2+1); animsplus(flammes, anim, 2, 1, x, y); } } else if (caselibre>0 && pl[x][y].elem!=mur) { tue(x, y, n); anim = (j==lflammes) ? (i+3) : (i/2+1); animsplus(flammes, anim, 2, 1, x, y); } else if (pl[x][y].elem==mur) { int animbrule=pl[x][y].frame+1; tue(x, y, n); if (animbrulenanims && mur->anims[animbrule]->nframes>1 && pl[x][y].anim==0) { animsplus(mur, animbrule, 2, 1, x, y); pl[x][y].anim=animbrule; pl[x][y].frame=mur->anims[animbrule]->nframes-1; } break; } else if (type==DESTRUCTIBLE) { tue(x, y, n); detruitbloc(x, y); if (sup) { anim = (j==lflammes) ? (i+3) : (i/2+1); animsplus(flammes, anim, 2, 1, x, y); } else break; } else break; } } animsplus(bombe, 5, 2, 1, ox, oy); return; } /*--Rafraichir l'écran (à chaque frame), suivant le mode--*/ int rafraichit(void) { if (dblebuf) { SDL_Flip(ecran); nrsrect=0; nrs=!nrs; } else { SDL_UpdateRects(ecran, nrsrect, rsrect); nrsrect=0; nrs=0; } return; } /*--Dessine la jauge d'énergie du joueur n à droite de l'écran--*/ void jauge(int n) { SDL_Rect jauge; SDL_Rect energie; jauge.y=n*48+114; jauge.x=523; jauge.h=10; jauge.w=106; energie.y=n*48+116; energie.x=525; energie.h=6; energie.w=102; if (!(perso[n].statut&VIVANT)) { SDL_FillRect(ecran, &jauge, 1); return; } if (perso[n].pouvactif[0]) blitsprit(sprit[n], ICONES, 2*((compteur/3)%2), 567, 48*n+80); else if (perso[n].energie>=perso[n].pouv[0].energie) blitsprit(sprit[n], ICONES, 0, 567, 48*n+80); else blitsprit(sprit[n], ICONES, 2, 567, 48*n+80); if (perso[n].pouvactif[1]) blitsprit(sprit[n], ICONES, 1+2*((compteur/3)%2), 599, 48*n+80); else if (perso[n].energie>=perso[n].pouv[1].energie) blitsprit(sprit[n], ICONES, 1, 599, 48*n+80); else blitsprit(sprit[n], ICONES, 3, 599, 48*n+80); energie.w=perso[n].energie/2.5; SDL_FillRect(ecran, &jauge, 1); SDL_FillRect(ecran, &energie, 2); return; } /*--Dessine la bande de droite (jauges, etc.)--*/ void dessinebande(void) { int i; SDL_Rect recdroite={512, 0, 128, 480}; SDL_Rect recbande={512, 0, 128, 80}; SDL_FillRect(ecran, &recdroite, 0); SDL_BlitSurface(bande, NULL, ecran, &recbande); rsrectplus(recdroite.x, recdroite.y, recdroite.w, recdroite.h); for (i=0; inanims<=ANIM_MORT) blitsprit(bombe, 7, (compteur/3)%4, 525, y); else if (AGONIE <= perso[i].animdroite) { blitsprit(sprit[i], ANIM_MORT, (perso[i].animdroite-AGONIE)/3, 525, y); if ( (++perso[i].animdroite - AGONIE)/3 >= sprit[i]->anims[ANIM_MORT]->nframes) perso[i].animdroite=ANIM_MORT; } else blitsprit(sprit[i], ANIM_MORT, sprit[i]->anims[ANIM_MORT]->nframes-1, 525, y); } else { if (perso[i].animdroite>=sprit[i]->nanims) perso[i].animdroite=BAS; blitsprit(sprit[i], perso[i].animdroite, (compteur/4) % sprit[i]->anims[perso[i].animdroite]->nframes, 525, y); } rsrect[nrsrect].x=523; rsrect[nrsrect].y=y; rsrect[nrsrect].w=106; rsrect[nrsrect].h=32+12; nrsrect++; } } /*--Annonce que tout devra être redessiné à la prochaine frame--*/ void rdtout(void) { int x, y; for (y=0; y<15; y++) for (x=0; x<16; x++) { if (pl[x][y].type==TUNNEL) { rstunnel[nrs][ntunnel[nrs]].x=x; rstunnel[nrs][ntunnel[nrs]].y=y; ntunnel[nrs]++; } else { rscase[nrs][nrscase[nrs]].x=x; rscase[nrs][nrscase[nrs]].y=y; nrscase[nrs]++; } } return; } /*--Redessiner les cases de décor--*/ void rdplateau(int rien) { nrscase[0]=0; nrscase[1]=0; ntunnel[0]=0; ntunnel[1]=0; nrsrect=0; rdtout(); if (dblebuf) { nrs = !nrs; rdtout(); } return; } /*--Gère les bombes--*/ void anibombes() { Bombelist * anibombes2(int n, Bombe * b); void anibombes3(int n, Bombelist * b); int i=0; Bombelist * imminent[NB_PERSO]; while (isuiv; if (b->rebours) { if (b->rebours>0) { anim= (5 * (REBOURS - b->rebours)) / REBOURS; b->rebours--; frame=((REBOURS - b->rebours) /3) % bombe->anims[anim]->nframes; } else { anim=7; frame=(compteur/3)%bombe->anims[anim]->nframes; } rscaseplus(b->pos.x, b->pos.y); blitsprit(bombe, anim, frame, b->pos.x*32, b->pos.y*32); return anibombes2(n,suiv); } else { Bombelist * nouv=(Bombelist *)malloc(sizeof(Bombelist)); nouv->contenu=b; nouv->suiv=anibombes2(n,suiv); return nouv; } } void anibombes3(int n, Bombelist * bl) { Bombelist * suiv; if (bl==NULL) return; suiv=bl->suiv; explose (n,bl->contenu); free(bl); anibombes3(n,suiv); return; } /*--Gère la structures anims--*/ void anime(Anims * a) { Anims * prec; /* On parcourt la liste des animations en ordre inverse pour que les plus récentes soient affichées au-dessus des plus anciennes */ if (a==NULL) return; prec=a->prec; rscaseplus(a->pos.x, a->pos.y); blitsprit(a->sprite, a->anim, a->frame, a->pos.x*32, a->pos.y*32); if (a->vitesse) a->compteur++; if (a->compteur==a->vitesse) { a->compteur=0; if (a->frame < a->sprite->anims[a->anim]->nframes-1) a->frame++; else { a->frame=0; if (a->duree) { a->duree--; if (!a->duree) animsmoins(a); } } } anime(prec); return; } /*--trie les volontés de déplacement des joueurs--*/ void mouvement(int n, int dir) { int x, y, stat; x=perso[n].pos.x+dx[dir]; y=perso[n].pos.y+dy[dir]; if (perso[n].statut & DEGUISE) pl[perso[n].pos.x][perso[n].pos.y].type=perso[n].pouvoirparam; stat=libre(x, y, dir); if (stat>0) perso[n].mv=1; else if (perso[n].statut & FURIEDESTRUCTRICE && stat==-1) { detruitbloc(x, y); bruitsplus(s_expl, 1); perso[n].mv=1; } else if (perso[n].statut & PASSEMURAILLES && 0<=perso[n].pos.x+dx[dir] && perso[n].pos.x+dx[dir]<16 && 0<=perso[n].pos.y+dy[dir] && perso[n].pos.y+dy[dir]<15) perso[n].mv=1; if (perso[n].statut & DEGUISE) { perso[n].pouvoirparam=pl[perso[n].pos.x][perso[n].pos.y].type; pl[perso[n].pos.x][perso[n].pos.y].type=CAMOUFL; } return; } /*--trie les commandes des joueurs et renvoie un bitmask--*/ int commande(int n) { int cmd=0x0; perso[n].cmd.precedent=perso[n].cmd.actif; if (perso[n].joueurIA) return perso[n].cmd.actif=gamelogic_main(n); else if (perso[n].cmd.joy==NULL) { if (clavier[perso[n].cmd.haut]==SDL_PRESSED) cmd|=CMD_HAUT; if (clavier[perso[n].cmd.bas]==SDL_PRESSED) cmd|=CMD_BAS; if (clavier[perso[n].cmd.gauche]==SDL_PRESSED) cmd|=CMD_GAUCHE; if (clavier[perso[n].cmd.droite]==SDL_PRESSED) cmd|=CMD_DROITE; if (clavier[perso[n].cmd.b1]==SDL_PRESSED) cmd|=CMD_B1; if (clavier[perso[n].cmd.b2]==SDL_PRESSED) cmd|=CMD_B2; } else { int var=SDL_JoystickGetAxis(perso[n].cmd.joy, 1); if (var < -100) cmd|=CMD_HAUT; if (var > 100) cmd|=CMD_BAS; var=SDL_JoystickGetAxis(perso[n].cmd.joy, 0); if (var < -100) cmd|=CMD_GAUCHE; if (var > 100) cmd|=CMD_DROITE; if (SDL_JoystickGetButton(perso[n].cmd.joy, 0)) cmd|=CMD_B1; if (SDL_JoystickGetButton(perso[n].cmd.joy, 1)) cmd|=CMD_B2; } return perso[n].cmd.actif=cmd; } /*--Gère les commandes des joueurs--*/ void touches(int n) { int p=0; int cmd=commande(n); if (!danslemenu) { if (cmd&CMD_B2) { p=1; if (cmd&CMD_GAUCHE) pouvoirplus(n, 0, 1); if (cmd&CMD_DROITE) pouvoirplus(n, 1, 1); if (cmd&CMD_HAUT) pouvoirplus(n, 2, 1); if (cmd&CMD_BAS) pouvoirplus(n, 3, 1); } } if (p); else if (cmd&CMD_HAUT && !perso[n].mv) { perso[n].dir=HAUT; mouvement(n, HAUT); } else if (cmd&CMD_BAS && !perso[n].mv) { perso[n].dir=BAS; mouvement(n, BAS); } else if (cmd&CMD_GAUCHE && !perso[n].mv) { perso[n].dir=GAUCHE; mouvement(n, GAUCHE); } else if (cmd&CMD_DROITE && !perso[n].mv) { perso[n].dir=DROITE; mouvement(n, DROITE); } if (!danslemenu) if (cmd&CMD_B1) { if (perso[n].statut & DETONATEUR) { Bombe * pt = perso[n].bombes; evtsplus(restorestatut, n, 0, 0, 6, 1, DETONATEUR, APRES, NULL); while (pt) { if (pt->rebours==-1) pt->rebours=0; pt=pt->suiv; } } else if(!(perso[n].statut&PASBOMBES)) posebombe(perso[n].pos.x, perso[n].pos.y, n); } return; } /*--Écran de menu des choix de personnages--*/ int choix(char *nom, char *image) { int i; FILE *niveau; char chemin[256]; SDL_Rect recfond; SDL_Color pal[255]; danslemenu=2; compteur=0; nrsrect=0; nrscase[0]=0; nrscase[1]=0; nrs=0; ntunnel[0]=0; ntunnel[1]=0; options=0; encore=1; videcran(); if (Mix_PlayingMusic) Mix_HaltMusic(); //if (avecmusique) Mix_PlayMusic(muschoix, -1); for (i=0; iformat->palette->colors, decl, fondecran->format->palette->ncolors); decl+=fondecran->format->palette->ncolors; charge_graphs(niveau); charge_sprites(sprit, spritliste, NB_PERSO); charge_sprites(fauxsprit, persoliste, nsprit); for (i=0; iformat->palette->ncolors; i++) { SDL_Color *colors=ecran->format->palette->colors; float moy=(colors[i].r+colors[i].g+colors[i].b)/3.0; moy=((moy-30-127)*0.68)+127; /* luminosité -20 contraste -40 */ pal[i-1].r= moy>=225 ? 255 : moy+30; pal[i-1].g= moy; pal[i-1].b= moy<=30 ? 0 : moy-30; } SDL_SetColors(ecran, pal, 1, 256); rdplateau(0); do { ajustevitesse(); if (compteur<65536) compteur++; else compteur=0; dessinecase(nrscase[nrs], rscase[nrs]); if (dblebuf) dessinecase(nrscase[!nrs], rscase[!nrs]); nrscase[nrs]=0; anime(animsfin); SDL_PumpEvents(); clavier=SDL_GetKeyState(NULL); for (i=0; iformat->palette->colors, decl, fondecran->format->palette->ncolors); decl+=fondecran->format->palette->ncolors; if (!principal) { for (i=0; ipos.x, y=e->pos.y, p=e->proprietaire, param=pl[x][y].params[0]; if (param==SUIVANT) { encore=0; bruitsplus(s_teleport, 1); } else if (MINNBproprietaire=i; /* ??? */ } if (!n_restant) { encore=0; if (Mix_PlayingMusic) Mix_HaltMusic(); } else bruitsplus(s_teleport, 1); } return; } /*--Boucle principale du jeu--*/ int jeu(void) { paletsg pal; int preums=1; #ifdef DEBUG int i; Uint32 stat[10000]; int nstat=0; int nral=0; float moy=0; #endif if (!dblebuf) pal=changepalette(0.0, 0.0, 0.0, 1, 256, 256, 256, 0); /* tout noir */ rdplateau(0); bruitsplus(s_debut, 1); do { int i=0; #ifdef DEBUG if (nstat<10000) stat[nstat++]=ajustevitesse(); else ajustevitesse(); #else ajustevitesse(); #endif if (compteur<65536) compteur++; else compteur=0; dessinecase(nrscase[nrs], rscase[nrs]); if (dblebuf) dessinecase(nrscase[!nrs], rscase[!nrs]); nrscase[nrs]=0; SDL_PumpEvents(); clavier=SDL_GetKeyState(NULL); agit(evts[AVANT], AVANT); anime(animsfin); anibombes(); while (iVITESSE) nral++; } moy /= (float)nstat; printf("Statistiques sur %i rafraichissements d'écran:\n", nstat); printf("%.2f frames par seconde en moyenne, ", 1000/moy); printf("limitées par le maximum de %i fps\n", 1000/VITESSE); printf("%i frame%s(%.2f%%) étai%st au-delà du maximum.\n", nral, nral>1 ? "s " : " ", (100.0*nral)/nstat, nral>1 ? "en" : ""); #endif reinit(); SDL_FreeSurface(bande); // if (!encore) bruitsplus(s_fin, 1); if (clavier[SDLK_F8]==SDL_PRESSED) { while(clavier[SDLK_F8]==SDL_PRESSED) { SDL_PumpEvents(); clavier=SDL_GetKeyState(NULL); } detruit_sprites(); return 2; } else if (clavier[SDLK_ESCAPE]==SDL_PRESSED) { while(clavier[SDLK_ESCAPE]==SDL_PRESSED) { SDL_PumpEvents(); clavier=SDL_GetKeyState(NULL); } return 0; } else return 1; } /*--Initialisation de chaque partie--*/ int initpartie(void) { int i; FILE *niveau; char chemin[256]; char nomniveau[256]; enpause=0; if (!choisi) { int ret; do ret=choix("choix.niv", "Choix.bmp"); while (ret==2); if (ret==1) return 0; } i=aleat(nb_niveaux); strcpy(nomniveau, niveaux[i]); //printf("C'est parti : niveau %s [%i/%i].\n", nomniveau, i, nb_niveaux); videcran(); reinit(); detruit_sprites(); couleurs = charge_sprite("infos.spr", decl); sprintf(chemin, "%s/%s", prefixeniv, nomniveau); niveau = fopen(chemin, "r"); if (niveau==NULL) erreur("Impossible d'ouvrir le niveau", nomniveau); sprintf(chemin, "%s/Bande.bmp", prefixeimg); bande=SDL_LoadBMP(chemin); if (bande==NULL) erreur("Impossible de charger l'image", chemin); SDL_SetColors(ecran, bande->format->palette->colors, decl, bande->format->palette->ncolors); decl+=bande->format->palette->ncolors; charge_graphs(niveau); charge_sprites(sprit, spritliste, NB_PERSO); for (i=0; i=sprit[n]->nanims ? BAS : GAGNE; r=3; p=1; if (modejeu==MODE_STD) score[n]++; } for (i=0; i=16) { for (j=0; jscore[i]-15) score[j]-=score[i]-15; else score[j]=0; } for (i=0; i=0; i--) { int ord=440-40*(NB_PERSO-i-1); blitsprit(sprit[i], BAS, 0, 64, ord); for (j=0; janims[a]->nframes*r+p; i++) { SDL_PumpEvents(); SDL_FillRect(ecran, &g, 0); if (strcmp(gagnant->nom,"Magus")) /* Le gagnant n'est pas Magus */ blitsprit(gagnant, a, i%gagnant->anims[a]->nframes, g.x, g.y); else { /* C'est un bricolage pour l'anim de Magus */ int u=i/2; if (u>=14) u = (u < 22) ? (6 + u%2) : (u - 8); if (u < gagnant->anims[a]->nframes) blitsprit(gagnant, a, u, g.x, g.y); } SDL_Flip(ecran); SDL_Delay(70); } SDL_Delay(500); /* Match fini ? */ for (i=0, n=0; iscore[n]) n=i; if (score[n]>=NROUNDS) { matchfini=1; for (i=0; iscore[n]-1-pointdavance && i!=n) matchfini=0; if (matchfini) { videcran(); sprintf(nom, "%s", sprit[n]->nom); nom[0]=toupper(nom[0]); // printf("Gagnant joueur %i, personnage %s.\n", n+1, sprit[n]->nom); printf("Gagnant joueur %i, personnage %s.\n", n+1, nom); // strcpy(texte[0], sprit[n]->nom); strcpy(texte[0], nom); for (j=1; j<7; j++) strcpy(texte[j],"\0"); sprintf(texte[7], "Wins !!!"); // sprintf(chemin, "%s.bmp", sprit[n]->nom); sprintf(chemin, "%s.bmp", nom); ecrantexte(texte, chemin, 8, 0); } } detruit_sprites(); clavier=SDL_GetKeyState(NULL); if (matchfini) return 1; if (clavier[SDLK_SPACE]==SDL_PRESSED) { while(clavier[SDLK_SPACE]==SDL_PRESSED) { SDL_PumpEvents(); clavier=SDL_GetKeyState(NULL); } return 2; } else if (clavier[SDLK_ESCAPE]==SDL_PRESSED) { while(clavier[SDLK_ESCAPE]==SDL_PRESSED) { SDL_PumpEvents(); clavier=SDL_GetKeyState(NULL); } return 1; } return 2; } int main(int argc, char **argv) { int i; int ret; int canal; char textecr[8][20], chemin[256]; chargeconfig(); sprintf(prefixeniv, "%s/Niveaux", repertoire); sprintf(prefixeimg, "%s/Decors", repertoire); sprintf(prefixespr, "%s/Sprites", repertoire); sprintf(prefixeson, "%s/Bruitages", repertoire); VITESSE=1000/VITESSE; spritliste=(char **)calloc(8, sizeof(char *)); for (i=0; i<8; i++) spritliste[i]=(char *)calloc(256, sizeof(char)); for (i=1; i