2019-12-03 19:53:30 +01:00
|
|
|
#include "ennemi.h"
|
|
|
|
#include "mario.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "tile.h"
|
|
|
|
#include "world.h"
|
|
|
|
#include "score.h"
|
2020-02-15 13:41:50 +01:00
|
|
|
#include <base.h>
|
2020-01-29 14:34:47 +01:00
|
|
|
#include <camera.h>
|
2020-02-15 13:41:50 +01:00
|
|
|
#include <level.h>
|
|
|
|
#include <gint/std/string.h>
|
2020-02-25 18:42:40 +01:00
|
|
|
#include <constants.h>
|
2019-12-03 19:53:30 +01:00
|
|
|
|
2019-12-04 19:27:27 +01:00
|
|
|
#include <stdbool.h>
|
2019-12-03 19:53:30 +01:00
|
|
|
|
2020-02-25 18:42:40 +01:00
|
|
|
const int ennemi_widths [NOMBRE_ENNEMIS] = {0, 8, 8, 8, 8 , 8, 8};
|
|
|
|
//const int ennemi_heights[NOMBRE_ENNEMIS] = {0, 8, 12, 9, 12, 9, 8};
|
|
|
|
const int ennemi_heights[NOMBRE_ENNEMIS] = {0, 8, 8, 8, 8, 8, 8};
|
2019-12-11 16:31:18 +01:00
|
|
|
|
2020-02-29 18:24:33 +01:00
|
|
|
void ennemiDisplay(ennemi_t const * e)
|
2019-12-03 19:53:30 +01:00
|
|
|
{
|
2020-02-25 18:42:40 +01:00
|
|
|
if (e->type==NONE) return;
|
|
|
|
if (e->b.x<=cameraX(0)-e->b.w || e->b.x>=cameraX(0)+127) return; // do not draw if out of the screen
|
2019-12-16 19:23:36 +01:00
|
|
|
|
2020-02-25 18:42:40 +01:00
|
|
|
{// draw
|
|
|
|
int tx=0, ty=0, dsx=0, dsy=0;
|
|
|
|
tileset_t t={0,ennemi_widths[e->type], ennemi_heights[e->type],1};
|
|
|
|
switch (e->type)
|
|
|
|
{
|
|
|
|
case GOOMBA_ID:
|
|
|
|
{
|
|
|
|
extern image_t img_goomba;
|
|
|
|
t.sheet=&img_goomba;
|
|
|
|
tx = e->life*(1+(time_id/10)%2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KOOPA_V_ID:
|
|
|
|
{
|
|
|
|
extern image_t img_koopa_verte;
|
|
|
|
t.sheet=&img_koopa_verte;
|
|
|
|
t.height=ennemi_heights[KOOPA_V_ID]+ennemi_heights[KOOPA_V_ID]/2;
|
|
|
|
tx = (1+e->p1)+(time_id/8)%2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KOOPA_R_ID:
|
|
|
|
{
|
|
|
|
extern image_t img_koopa_rouge;
|
|
|
|
t.sheet=&img_koopa_rouge;
|
|
|
|
t.height=ennemi_heights[KOOPA_R_ID]+ennemi_heights[KOOPA_R_ID]/2;
|
|
|
|
tx = (1+e->p1)+(time_id/8)%2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CARAPACE_VERTE:
|
|
|
|
{
|
|
|
|
extern image_t img_carapace_verte;
|
|
|
|
t.sheet=&img_carapace_verte;
|
|
|
|
t.height=ennemi_heights[CARAPACE_VERTE]+ennemi_heights[CARAPACE_VERTE]/8;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CARAPACE_ROUGE:
|
|
|
|
{
|
|
|
|
extern image_t img_carapace_rouge;
|
|
|
|
t.sheet=&img_carapace_rouge;
|
|
|
|
t.height=ennemi_heights[CARAPACE_ROUGE]+ennemi_heights[CARAPACE_ROUGE]/8;
|
|
|
|
}
|
|
|
|
break;
|
2019-12-04 19:27:27 +01:00
|
|
|
|
2020-02-25 18:42:40 +01:00
|
|
|
case PLANTE_ID:
|
|
|
|
{
|
|
|
|
extern image_t img_plante;
|
|
|
|
t.sheet=&img_plante;
|
2020-03-10 19:20:06 +01:00
|
|
|
t.width*=2;
|
2020-03-07 15:22:39 +01:00
|
|
|
dsx=-4;
|
2020-02-25 18:42:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
tileDraw(e->b.x-cameraX(0)+dsx, e->b.y-cameraY(mario.p.y)+dsy, &t, tx, ty);
|
|
|
|
}
|
2019-12-03 19:53:30 +01:00
|
|
|
}
|
2019-12-04 19:27:27 +01:00
|
|
|
|
2020-03-10 19:20:06 +01:00
|
|
|
void plante_tour(ennemi_t *e)
|
2020-03-07 15:22:39 +01:00
|
|
|
{
|
|
|
|
if (e->type==PLANTE_ID)
|
|
|
|
{
|
|
|
|
e->p1++;
|
2020-03-10 19:20:06 +01:00
|
|
|
e->p1%=PLANTE_NLAPS;
|
2020-03-07 15:22:39 +01:00
|
|
|
if (0<=e->p1 && e->p1<35) // (plante en bas, en attente)
|
|
|
|
{
|
|
|
|
if (abs(mario.p.x-e->b.x)<15) e->p1=0;
|
|
|
|
}
|
2020-03-10 19:20:06 +01:00
|
|
|
if (35<=e->p1 && e->p1<58)
|
2020-03-07 15:22:39 +01:00
|
|
|
{
|
|
|
|
if ((e->p1+1)%3==0) e->b.y++;
|
|
|
|
}
|
2020-03-10 19:20:06 +01:00
|
|
|
if (58<=e->p1 && e->p1<75){} // plante en attente en haut
|
|
|
|
if (75<=e->p1 && e->p1<98)
|
2020-03-07 15:22:39 +01:00
|
|
|
{
|
|
|
|
if (e->p1%3==0) e->b.y--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 20:43:35 +01:00
|
|
|
bool ennemi_check_collision(ennemi_t *e) { return (boxContact(&e->b, &mario.p)); }
|
2019-12-04 19:27:27 +01:00
|
|
|
|
2020-02-16 20:43:35 +01:00
|
|
|
void hurtMario()
|
2020-02-25 18:42:40 +01:00
|
|
|
{
|
|
|
|
if (mario.size==M_SMALL && mario_immunity==0)
|
2020-01-06 18:43:36 +01:00
|
|
|
{mario_dead=1;finish_level=0;}
|
2020-02-25 18:42:40 +01:00
|
|
|
else marioSmaller();
|
2019-12-05 19:24:16 +01:00
|
|
|
}
|
2019-12-04 19:27:27 +01:00
|
|
|
|
2020-02-16 20:43:35 +01:00
|
|
|
void ennemiMove(ennemi_t *e)
|
2019-12-03 19:53:30 +01:00
|
|
|
{
|
2020-03-04 15:08:35 +01:00
|
|
|
if (!(e->b.x<=cameraX(0)-e->b.w || e->b.x>=cameraX(0)+127)) e->discovered=1; // for security, tag as discover all drawed ennemies
|
|
|
|
|
2020-03-07 15:22:39 +01:00
|
|
|
if (e->life==DEAD && e->type!=NONE) // dying animation
|
2020-02-29 18:24:33 +01:00
|
|
|
{
|
|
|
|
if (e->p1==0)
|
|
|
|
{
|
2020-03-07 15:22:39 +01:00
|
|
|
e->b.vx=2*sgn(e->b.vx);
|
2020-02-29 18:24:33 +01:00
|
|
|
e->b.vy=5;
|
|
|
|
}
|
|
|
|
e->p1++;
|
|
|
|
e->b.vy--;
|
|
|
|
e->b.y+=e->b.vy;
|
|
|
|
e->b.x+=e->b.vx;
|
|
|
|
if (e->p1>=30) e->type=NONE; // died 1.5 sec before
|
|
|
|
}
|
2019-12-03 19:53:30 +01:00
|
|
|
|
2020-02-16 20:43:35 +01:00
|
|
|
if (e->b.x<cameraX()+128+30 && e->b.x>cameraX()-30)
|
2020-02-25 18:42:40 +01:00
|
|
|
e->discovered=1;
|
2020-02-16 20:43:35 +01:00
|
|
|
//if (e->b.x+e->b.w<=worldGetCell_real_x0())
|
2020-01-13 20:24:06 +01:00
|
|
|
// e->type=NONE;
|
2020-01-06 18:43:36 +01:00
|
|
|
if (e->discovered==0)
|
2020-02-25 18:42:40 +01:00
|
|
|
return;
|
2020-01-06 18:43:36 +01:00
|
|
|
if (e->life==DEAD)
|
2020-02-25 18:42:40 +01:00
|
|
|
return;
|
2020-01-06 18:43:36 +01:00
|
|
|
// e->type=NONE;
|
|
|
|
if (e->type==NONE)
|
2020-02-25 18:42:40 +01:00
|
|
|
return;
|
2019-12-11 16:31:18 +01:00
|
|
|
|
2020-02-16 20:43:35 +01:00
|
|
|
bool e_hitMario=ennemi_check_collision(e);
|
|
|
|
if (e_hitMario&&mario_starMode)
|
2020-01-06 18:43:36 +01:00
|
|
|
{
|
|
|
|
e->life=DEAD;
|
|
|
|
e->p1=0;
|
2020-02-25 18:42:40 +01:00
|
|
|
scoreAdd(KILL_ENNEMI);
|
2020-01-06 18:43:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2019-12-11 16:31:18 +01:00
|
|
|
|
2020-03-07 15:22:39 +01:00
|
|
|
for (int i=0; i<ennemis_global_size; i++) // physique des carapaces (collisions avec les autres)
|
2020-01-06 18:43:36 +01:00
|
|
|
{
|
|
|
|
ennemi_t* t=&ennemis_global[i];
|
2020-02-16 12:51:27 +01:00
|
|
|
if (t->type!=NONE)
|
2020-01-06 18:43:36 +01:00
|
|
|
{
|
2020-02-16 12:51:27 +01:00
|
|
|
e->b.x+=sgn(e->b.vx)*(abs(e->b.vx)+(time_id%2))/2;
|
2020-02-16 20:43:35 +01:00
|
|
|
const int contact=boxContact(&e->b, &t->b);
|
2020-02-16 12:51:27 +01:00
|
|
|
e->b.x-=sgn(e->b.vx)*(abs(e->b.vx)+(time_id%2))/2;
|
|
|
|
if (contact && t->life!=DEAD)
|
2020-01-06 18:43:36 +01:00
|
|
|
{
|
|
|
|
if (e->type!=CARAPACE_VERTE && e->type!=CARAPACE_ROUGE)
|
|
|
|
{
|
|
|
|
e->b.vx=0;
|
|
|
|
e->b.vy=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (t->type==CARAPACE_VERTE || t->type==CARAPACE_ROUGE)
|
|
|
|
{
|
|
|
|
e->p1*=-1;
|
|
|
|
e->b.vx=6*e->p1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t->life=DEAD;
|
|
|
|
t->p1=0;
|
2020-02-25 18:42:40 +01:00
|
|
|
scoreAdd(KILL_ENNEMI);
|
2020-01-06 18:43:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-07 15:22:39 +01:00
|
|
|
|
2020-01-06 18:43:36 +01:00
|
|
|
int previous_case=-5;
|
|
|
|
for (int j=0; j<e->b.h; j++)
|
|
|
|
{
|
|
|
|
if ((e->b.x+j)/8!=previous_case)
|
|
|
|
{
|
|
|
|
previous_case=(e->b.x+j)/8;
|
2020-03-07 15:22:39 +01:00
|
|
|
gift_t * c=(gift_t *)worldGetCell(e->b.x+j, e->b.y-1);
|
2020-01-28 21:32:58 +01:00
|
|
|
if ((c->type==GIFT || c->type==BRICK) && (c->time_hit_id || c->state) && e->life!=DEAD)
|
|
|
|
{
|
2020-03-07 15:22:39 +01:00
|
|
|
e->life=e->p1=DEAD;
|
2020-02-25 18:42:40 +01:00
|
|
|
scoreAdd(KILL_ENNEMI);
|
2020-01-28 21:32:58 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-01-06 18:43:36 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-05 19:24:16 +01:00
|
|
|
|
2020-02-29 19:01:17 +01:00
|
|
|
if (e->b.y<0) e->type=NONE;
|
2019-12-04 19:27:27 +01:00
|
|
|
|
2020-02-29 19:01:17 +01:00
|
|
|
const bool mario_fatal_hit = (mario.p.last_vy<=-2 || mario.p.vy<=-2);
|
|
|
|
switch (e->type) // move
|
2020-01-06 18:43:36 +01:00
|
|
|
{
|
2020-02-29 19:01:17 +01:00
|
|
|
case KOOPA_R_ID:
|
2020-03-07 15:22:39 +01:00
|
|
|
boxMove(&e->b);
|
2020-02-29 19:15:09 +01:00
|
|
|
if (e->b.vx)
|
|
|
|
{ // demi tour si au dessus du vide
|
2020-01-28 21:32:58 +01:00
|
|
|
int s=-1;
|
2020-02-29 19:01:17 +01:00
|
|
|
if (e->b.vx>0) s=e->b.w;
|
2020-01-28 21:32:58 +01:00
|
|
|
|
2020-02-29 19:15:09 +01:00
|
|
|
if (worldGetCellCategory(e->b.x+s, e->b.y-1)==CTG_EMPTY && sgn(e->b.vx)==sgn(s)) e->b.vx=(e->p1*=-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
case GOOMBA_ID:
|
|
|
|
case KOOPA_V_ID:
|
2020-03-07 15:22:39 +01:00
|
|
|
if (e->type!=KOOPA_R_ID) boxMove(&e->b);
|
2020-02-29 19:15:09 +01:00
|
|
|
if (e->b.vx==0) // demi tour si mur
|
|
|
|
{
|
|
|
|
if (e->p1==0) e->b.vx=e->p1=-1;
|
|
|
|
else e->b.vx=(e->p1*=-1);
|
2020-01-28 21:32:58 +01:00
|
|
|
}
|
2020-02-29 19:01:17 +01:00
|
|
|
break;
|
2020-01-28 21:32:58 +01:00
|
|
|
|
2020-02-29 19:01:17 +01:00
|
|
|
case CARAPACE_VERTE:
|
|
|
|
case CARAPACE_ROUGE:
|
2020-03-07 15:22:39 +01:00
|
|
|
boxMove(&e->b);
|
2020-01-06 18:43:36 +01:00
|
|
|
if (e->b.vx==0)
|
|
|
|
{
|
|
|
|
if (e->p1<2)
|
|
|
|
{
|
|
|
|
e->p1*=-1;
|
|
|
|
e->b.vx=6*e->p1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (e->p1>=2)
|
|
|
|
{
|
2020-02-29 19:01:17 +01:00
|
|
|
if ((e->p1++)==80)
|
2020-02-25 18:42:40 +01:00
|
|
|
{ // transformation carapace->koopa
|
|
|
|
e->type--;
|
2020-01-28 21:32:58 +01:00
|
|
|
e->b.h=ennemi_heights[e->type];
|
2020-02-25 18:42:40 +01:00
|
|
|
e->p1=e->b.vx=0;
|
2020-01-06 18:43:36 +01:00
|
|
|
}
|
|
|
|
}
|
2020-02-29 19:15:09 +01:00
|
|
|
break;
|
2020-03-07 15:22:39 +01:00
|
|
|
|
|
|
|
case PLANTE_ID:
|
|
|
|
plante_tour(e);
|
2020-02-29 19:01:17 +01:00
|
|
|
}
|
2019-12-07 19:26:55 +01:00
|
|
|
|
2020-02-29 19:01:17 +01:00
|
|
|
if (e_hitMario && mario_fatal_hit) switch (e->type) // mario attacks
|
|
|
|
{
|
|
|
|
case GOOMBA_ID:
|
|
|
|
e->life=DEAD;
|
|
|
|
e->p1=0;
|
|
|
|
scoreAdd(KILL_ENNEMI);
|
|
|
|
mario.p.vy=4;
|
|
|
|
mario.p.y=e->b.y+ennemi_heights[e->type]+1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KOOPA_V_ID:
|
|
|
|
case KOOPA_R_ID:
|
|
|
|
e->type++;
|
|
|
|
e->b.h=ennemi_heights[e->type];
|
|
|
|
e->p1=2;
|
|
|
|
e->b.vx=0;
|
|
|
|
scoreAdd(KILL_ENNEMI);
|
2020-03-10 19:20:06 +01:00
|
|
|
mario.p.vy=6;
|
2020-02-29 19:01:17 +01:00
|
|
|
mario.p.y=e->b.y+ennemi_heights[e->type]+1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CARAPACE_VERTE:
|
|
|
|
case CARAPACE_ROUGE:
|
|
|
|
if (e->p1==0 || e->p1>=2)
|
2020-01-06 18:43:36 +01:00
|
|
|
{
|
2020-02-29 19:01:17 +01:00
|
|
|
if (mario.p.x>=e->b.x) e->p1=-1;
|
|
|
|
if (mario.p.x<=e->b.x) e->p1=1;
|
|
|
|
e->b.vx=6*e->p1;
|
2020-03-04 15:08:35 +01:00
|
|
|
|
2020-03-10 19:20:06 +01:00
|
|
|
mario.p.vy=6;
|
2020-03-07 15:22:39 +01:00
|
|
|
mario.p.y=e->b.y+ennemi_heights[CARAPACE_VERTE];
|
2020-02-29 19:01:17 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-10 19:20:06 +01:00
|
|
|
e->p1=e->b.vx=mario.p.vx=0;
|
|
|
|
mario.p.vy=6;
|
2020-02-29 19:01:17 +01:00
|
|
|
mario.p.y=e->b.y+ennemi_heights[CARAPACE_VERTE]+1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-03-10 19:20:06 +01:00
|
|
|
case PLANTE_ID:
|
|
|
|
hurtMario();
|
|
|
|
break;
|
|
|
|
|
2020-02-29 19:01:17 +01:00
|
|
|
}
|
|
|
|
else if (e_hitMario) switch (e->type) // hurt mario
|
|
|
|
{
|
|
|
|
case GOOMBA_ID:
|
|
|
|
case KOOPA_V_ID:
|
|
|
|
case KOOPA_R_ID:
|
|
|
|
hurtMario();
|
|
|
|
break;
|
2020-01-12 12:45:42 +01:00
|
|
|
|
2020-02-29 19:01:17 +01:00
|
|
|
case CARAPACE_VERTE:
|
|
|
|
case CARAPACE_ROUGE:
|
|
|
|
if (e->p1==0 || e->p1>=2)
|
|
|
|
{
|
|
|
|
if (mario.p.x>=e->b.x) e->p1=-1;
|
2020-02-29 19:15:09 +01:00
|
|
|
else e->p1=1;
|
2020-02-29 19:01:17 +01:00
|
|
|
e->b.vx=6*e->p1;
|
|
|
|
if (mario_fatal_hit)
|
|
|
|
{
|
2020-03-10 19:20:06 +01:00
|
|
|
mario.p.vy=6;
|
2020-02-29 19:01:17 +01:00
|
|
|
mario.p.y=e->b.y+ennemi_heights[CARAPACE_VERTE];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // mario bounce
|
|
|
|
if (mario.p.x>=e->b.x) mario.p.x=e->b.x+e->b.w;
|
2020-02-29 19:15:09 +01:00
|
|
|
else mario.p.x=e->b.x-mario.p.w;
|
2020-03-10 19:20:06 +01:00
|
|
|
mario.p.vx=0;
|
2020-02-29 19:01:17 +01:00
|
|
|
}
|
2020-01-06 18:43:36 +01:00
|
|
|
}
|
2020-02-29 19:01:17 +01:00
|
|
|
else hurtMario();
|
|
|
|
break;
|
2020-03-10 19:20:06 +01:00
|
|
|
|
|
|
|
case PLANTE_ID:
|
|
|
|
hurtMario();
|
|
|
|
break;
|
2020-01-06 18:43:36 +01:00
|
|
|
}
|
2019-12-03 19:53:30 +01:00
|
|
|
}
|
2019-12-04 19:27:27 +01:00
|
|
|
|
2020-02-25 18:42:40 +01:00
|
|
|
// Global variables for ennemies
|
2019-12-03 19:53:30 +01:00
|
|
|
ennemi_t * ennemis_global=0;
|
|
|
|
int ennemis_global_size=0;
|
2020-02-25 18:42:40 +01:00
|
|
|
|
2020-02-16 20:43:35 +01:00
|
|
|
void ennemiesDisplay()
|
2019-12-03 19:53:30 +01:00
|
|
|
{
|
2020-02-25 18:42:40 +01:00
|
|
|
for (int i=0; i<ennemis_global_size; i++) ennemiDisplay(&ennemis_global[i]);
|
2019-12-16 19:23:36 +01:00
|
|
|
}
|
2020-02-01 14:36:34 +01:00
|
|
|
|
|
|
|
|
2020-02-25 18:42:40 +01:00
|
|
|
void ennemiesInit(ennemi_t * table, int s)
|
2020-02-01 14:36:34 +01:00
|
|
|
{
|
|
|
|
if (ennemis_global)
|
2020-03-07 15:22:39 +01:00
|
|
|
freeProf(ennemis_global);
|
2020-02-25 18:42:40 +01:00
|
|
|
ennemis_global_size=ennemis_global=0;
|
|
|
|
if (!s) return;
|
2020-02-03 11:12:54 +01:00
|
|
|
int size=sizeof(ennemi_t)*s;
|
2020-02-25 18:42:40 +01:00
|
|
|
if ((ennemis_global=mallocProf(size))==0) mallocError();
|
2020-02-03 11:12:54 +01:00
|
|
|
ennemis_global_size=s;
|
2020-02-01 14:36:34 +01:00
|
|
|
memcpy(ennemis_global, table, size);
|
2020-02-16 12:51:27 +01:00
|
|
|
}
|