NppClone/src/level.cpp

570 lines
17 KiB
C++

#include "parameters.h"
#include "level.h"
#include "player.h"
#include <azur/azur.h>
#include <azur/gint/render.h>
#include <num/num.h>
#include "utilities.h"
#include <cstdint>
#include <stdlib.h>
#include "player.h"
#define TILESIZE 16
extern struct Map map_level0;
extern struct Map map_level1;
extern struct Map map_level2;
extern struct Map map_level3;
extern struct Map map_level4;
extern struct Map map_level5;
extern bool drawbackground;
extern bool drawforeground;
extern bool drawnormals;
extern bool drawborders;
extern bool textbacktile;
extern bool textforetile;
extern uint16_t tilecolor;
extern std::vector<Border*> MyLevelBorders;
extern Player MyPlayer;
struct Map *map_level;
int tileXmin, tileXmax;
int tileYmin, tileYmax;
int XinTile, YinTile;
extern bopti_image_t img_selected;
Level::Level( )
{
map_level = &map_level0;
this->UpdateDataMap( );
}
Level::~Level( )
{
}
void Level::ChangeMap( int level )
{
if(level==0) map_level = &map_level0;
else if(level==1) map_level = &map_level1;
else if(level==2) map_level = &map_level2;
else if(level==3) map_level = &map_level3;
else if(level==4) map_level = &map_level4;
else if(level==5) map_level = &map_level5;
else map_level = &map_level0;
this->UpdateDataMap( );
}
void Level::UpdateDataMap( void )
{
for(int i=0; i<map_level->w; i++)
{
for(int j=0; j<map_level->h; j++)
{
uint16_t index = j * map_level->w + i;
uint16_t currentTile = map_level->layers[1][ index ];
if (currentTile==31)
{
MyPlayer.currx = ((float) (i + 0.5f))*16.0f;
MyPlayer.curry = ((float) (j + 0.5f))*16.0f;
MyPlayer.vx = 0.0f;
MyPlayer.vy = 0.0f;
MyPlayer.Update( 0.0f );
}
}
}
}
void Level::Render( void )
{
for(int u=!drawbackground; u<map_level->nblayers-!drawforeground;u++)
{
for(int i=0; i<map_level->w; i++)
{
for(int j=0; j<map_level->h; j++)
{
uint16_t index = j * map_level->w + i;
int16_t currentTile = map_level->layers[u][ index ];
if (currentTile!=-1)
{
uint16_t xtile = (currentTile % map_level->tileset_size) * 16;
uint16_t ytile = (currentTile / map_level->tileset_size) * 16;
if (u==0) azrp_subimage_rgb16_dye( i*16, j*16, map_level->tileset, xtile, ytile, 16, 16, IMAGE_DYE | IMAGE_NOCLIP_INPUT, tilecolor );
else azrp_subimage_rgb16( i*16, j*16, map_level->tileset, xtile, ytile, 16, 16, DIMAGE_NONE | IMAGE_NOCLIP_INPUT );
#if(DEBUG_MODE)
if (textbacktile) azrp_draw_text( i*16, j*16, "%d", GetTileBackgroundINT( i, j ) );
if (textforetile) azrp_draw_text( i*16+8, j*16+8, "%d", GetTileForegroundINT( i, j ) );
#endif
}
}
}
}
#if(DEBUG_MODE)
if (drawborders)
for( unsigned int i=0; i<MyLevelBorders.size(); i++)
azrp_line( (int) MyLevelBorders[i]->A.x, (int) MyLevelBorders[i]->A.y,
(int) MyLevelBorders[i]->B.x, (int) MyLevelBorders[i]->B.y,
MyLevelBorders[i]->color );
if (drawnormals)
for( unsigned int i=0; i<MyLevelBorders.size(); i++)
azrp_line( ((int) MyLevelBorders[i]->A.x+(int) MyLevelBorders[i]->B.x)/2, ((int) MyLevelBorders[i]->A.y+(int) MyLevelBorders[i]->B.y)/2,
((int) MyLevelBorders[i]->A.x+(int) MyLevelBorders[i]->B.x)/2 + (int) MyLevelBorders[i]->N.x/2, ((int) MyLevelBorders[i]->A.y+(int) MyLevelBorders[i]->B.y)/2 + (int) MyLevelBorders[i]->N.y/2,
C_BLUE );
#endif
}
void Level::RenderSelected( uint8_t i, uint8_t j )
{
}
void Level::Update( float dt )
{
UpdateBorders( );
}
/*RETURN the type of tile located in the background for the point x, y using player coordinates (x=[0..25], y=[0..14]) */
/*the x and y correspond to hte integer part of MyPlayer.x and MyPlayer.y*/
int Level::GetTileBackgroundINT( uint8_t x, uint8_t y )
{
uint16_t index = y * map_level->w + x;
uint16_t currentTile = map_level->layers[0][ index ];
return currentTile;
}
/*RETURN the type of tile located in the foreground for the point x, y using player coordinates (x=[0..25], y=[0..14]) */
/*the x and y correspond to hte integer part of MyPlayer.x and MyPlayer.y*/
int Level::GetTileForegroundINT( uint8_t x, uint8_t y )
{
uint16_t index = y * map_level->w + x;
uint16_t currentTile = map_level->layers[1][ index ];
return currentTile;
}
/*RETURN the type of tile located in the background for the point x, y using screen coordinates (x=[0..396], y=[0..223]) */
int Level::GetTileBackground( uint16_t x, uint16_t y )
{
uint8_t tileX = x >> 4;
uint8_t tileY = y >> 4;
uint16_t index = tileY * map_level->w + tileX;
uint16_t currentTile = map_level->layers[0][ index ];
return currentTile;
}
/*RETURN the type of tile located in the foreground for the point x, y using screen coordinates (x=[0..396], y=[0..223]) */
int Level::GetTileForeground( uint16_t x, uint16_t y )
{
uint8_t tileX = x >> 4;
uint8_t tileY = y >> 4 ;
uint16_t index = tileY * map_level->w + tileX;
uint16_t currentTile = map_level->layers[1][ index ];
return currentTile;
}
bool CollisionSegSeg( Point2D A, Point2D B, Point2D C, Point2D D, Point2D *R )
{
Vector2D I, J;
I.x = B.x - A.x;
I.y = B.y - A.y;
if (I.x==0 && I.y==0) return false;
J.x = D.x - C.x;
J.y = D.y - C.y;
if (J.x==0 && J.y==0) return false;
libnum::num32 det;
det = I.x*J.y-I.y*J.x;
if (det==0) return false; // the segments are parallel
libnum::num32 m;
m = (I.x*A.y - I.x*C.y - I.y*A.x + I.y*C.x) / det;
libnum::num32 k;
k = (J.x*A.y - J.x*C.y - J.y*A.x + J.y*C.x) / det;
if ((m<libnum::num32(0) || m>libnum::num32(1) || k<libnum::num32(0) || k>libnum::num32(1)))
return false; // intersection of the lines, but not of the segments
(*R).x = C.x + k*J.x;
(*R).y = C.y + k*J.y;
return true;
}
/*RETURN true if the player can go in the target position*/
bool Level::CanGo( void )
{
Point2D PlayerOrigin, PlayerTarget;
PlayerOrigin.x = MyPlayer.currx;
PlayerOrigin.y = MyPlayer.curry;
PlayerTarget.x = MyPlayer.nextx;
PlayerTarget.y = MyPlayer.nexty;
if (PlayerTarget.x == PlayerOrigin.x && PlayerTarget.y == PlayerOrigin.y) return true; // velocity is 0 so Player.next = Player.Curr so we can stay here, that's obvious
if (MyLevelBorders.size() == 0) return true; // there is no surrounding border so no need to check if there are collisions (also obvious)
for (unsigned int i=0; i<MyLevelBorders.size(); i++)
{
Point2D A, B, I;
A.x = MyLevelBorders[i]->A.x;
A.y = MyLevelBorders[i]->A.y;
B.x = MyLevelBorders[i]->B.x;
B.y = MyLevelBorders[i]->B.y;
// Detection de collision entre [A,B] et [Player.Curr, Player.Next]
if (CollisionSegSeg( A, B, PlayerOrigin, PlayerTarget, &I ))
{
MyLevelBorders[i]->color = C_RED;
MyPlayer.nextx = I.x;
MyPlayer.nexty = I.y;
MyPlayer.vx = libnum::num32(0);
MyPlayer.vy = libnum::num32(0);
return false;
}
}
return true;
}
Border* Level::MakeBorder( libnum::num DX, libnum::num DY, float x1, float y1, float x2, float y2 )
{
Border *Bord = new Border();
Bord->A.x = DX + libnum::num(x1*15.0);
Bord->A.y = DY + libnum::num(y1*15.0);
Bord->B.x = DX + libnum::num(x2*15.0);
Bord->B.y = DY + libnum::num(y2*15.0);
Bord->N.x = Bord->A.y - Bord->B.y;
Bord->N.y = Bord->B.x - Bord->A.x;
Bord->color = C_GREEN;
return Bord;
}
void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum::num DeltaY )
{
Border *B1;
switch(currentTile)
{
case -1: break; // Empty background
case 0: break; // No borders (filling tile)
case 1:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
//45° diagonals
case 2:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 3:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 12:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 13:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
break;
//22.5° diagonals
case 4:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,0.5 );
MyLevelBorders.push_back(B1);
break;
case 5:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.5, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 6:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 1.0,0.5 );
MyLevelBorders.push_back(B1);
break;
case 7:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.5, 1.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 14:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.5, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 15:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 0.0,0.5 );
MyLevelBorders.push_back(B1);
break;
case 16:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.5, 0.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 17:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.5 );
MyLevelBorders.push_back(B1);
break;
// 67.5° Diagonals
case 24:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 34:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 0.5,0.0 );
MyLevelBorders.push_back(B1);
break;
case 25:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.5,1.0 );
MyLevelBorders.push_back(B1);
break;
case 35:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,0.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 26:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,1.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 36:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 0.5,0.0 );
MyLevelBorders.push_back(B1);
break;
case 27:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.5,1.0 );
MyLevelBorders.push_back(B1);
break;
case 37:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
break;
// Blocks with 3 sides
case 8:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 9:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 18:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 19:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
// Blocks with 2 sides
case 28:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 29:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 38:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 39:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 48:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 49:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
// Blocks with one single side
case 10:
case 44:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
MyLevelBorders.push_back(B1);
break;
case 11:
case 46:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 20:
case 47:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
MyLevelBorders.push_back(B1);
break;
case 21:
case 45:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
MyLevelBorders.push_back(B1);
break;
default:
break;
}
}
void Level::UpdateBorders( void )
{
for(unsigned int i=0; i<MyLevelBorders.size(); i++)
delete MyLevelBorders[i];
MyLevelBorders.clear();
uint16_t xp = MyPlayer.tileX;
uint16_t yp = MyPlayer.tileY;
uint16_t xmin = max( xp - 1, 0 );
uint16_t xmax = min( xp + 1, map_level->w-1 );
uint16_t ymin = max( yp - 1, 0 );
uint16_t ymax = min( yp + 1, map_level->h-1 );
// for( int i=10; i<map_level->w; i++)
for( int i=xmin; i<=xmax; i++)
{
//for( int j=10; j<map_level->h; j++)
for( int j=ymin; j<=ymax; j++)
{
uint16_t index = j * map_level->w + i;
int16_t currentTile = map_level->layers[0][ index ];
libnum::num DeltaX = libnum::num( i*16 );
libnum::num DeltaY = libnum::num( j*16 );
ConvertTileToBorder( currentTile, DeltaX, DeltaY );
}
}
}