/*
 * main.c
 *
 * Copyleft 2015-2016 by 240-185
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 */

//La librairie principale OSLib

#define _16bit OSL_PF_8888
#define spr_draw oslDrawImageXY

#define mapWidth 64
#define mapHeight 64
#define uDiv 1
#define vDiv 1
#define vMove 0.0
#define MAXSPRITES 1024
#define BRUNNI 0
#define DOORTYPELIKE 2

#include <oslib/oslib.h>
#include <oslib/libpspmath/pspmath.h>
#include <psputils.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspmpeg.h>
#include <pspdisplay.h>
#include <psprtc.h>
#include <psppower.h>
#include <pspfpu.h>
#include <pspgu.h>
#include <psptypes.h>


/*#include "mandatory_including.h"
#include "levels.h"*/



//les callbacks
PSP_MODULE_INFO("COGEEP", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
PSP_HEAP_SIZE_KB(-1024);

SceKernelUtilsMt19937Context ctx;

OSL_FONT *fonts[3];

int worldMap[mapWidth][mapHeight];
int worldSprites[mapWidth][mapHeight];
int worldVendings[mapWidth][mapHeight];
int worldPushable[mapWidth][mapHeight];
int worldDoorTimers[mapWidth][mapHeight];
int worldDoors[mapWidth][mapHeight];
int worldDiffs[mapWidth][mapHeight];

typedef struct {
  float x;
  float y;
  float speed;
  int texture;
  int wokenUp;
  int stunned;
  int health;
  int discovered;
} Sprite;

int recensedSprites[256];
int recensedTextures[256];

int spriteOrder[MAXSPRITES];
float spriteDistance[MAXSPRITES];

int floor_color[3] =  {108, 92, 80};
int ceiling_color[3] =  {128, 128, 128};

int startPosX=1;
int startPosY=1;
int startAngle=90;
int ammo=8, health=100, armor=0, coins=0;
int weaponPossessed[4]={1, 1, 0, 0};
int weapon=1;

int exit_callback(int arg1, int arg2, void *common) {
          sceKernelExitGame();
          return 0;
}

/* Callback thread */
int CallbackThread(SceSize args, void *argp) {
          int cbid;

          cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
          sceKernelRegisterExitCallback(cbid);

          sceKernelSleepThreadCB();

          return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void) {
          int thid = 0;

          thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
          if(thid >= 0) {
                    sceKernelStartThread(thid, 0, 0);
          }

          return thid;
}
// End Callback functs

int random(int max)
{
	//return (int)oslRandf(0,max);

	   u32 rand_val = sceKernelUtilsMt19937UInt(&ctx);
	   rand_val = rand_val % (max);
	   return (int)rand_val;
}

int initBarrels(Sprite *sprite, int diff)
{
	int i,j,k=0;

	for (i=0; i<MAXSPRITES; i++)
	{
		spriteOrder[i]=0;
		spriteDistance[i]=0;
		sprite[i].x=-1;
		sprite[i].y=-1;
		sprite[i].texture=0;
	}

	for (i=0; i<256; i++) recensedSprites[i]=0;

	for (i=0; i<mapWidth; i++)
	{
		for (j=0; j<mapHeight; j++)
		{
			worldDoors[i][j]=0;
			worldDoorTimers[i][j]=0;

			if (worldSprites[i][j] > 1)
			{
				if (worldSprites[i][j] < 129) worldMap[i][j]=1;


				if (worldDiffs[i][j] <= (diff-1))
				{
					sprite[k].x=i+0.5;
					sprite[k].y=j+0.5;
					sprite[k].texture = worldSprites[i][j]-1;
					sprite[k].wokenUp=0;
					sprite[k].stunned=0;

					switch(sprite[k].texture)
					{
						case 192:
							sprite[k].speed=0.02;
							sprite[k].health=12*diff;
							sprite[k].discovered=0;
							recensedSprites[193]++;
							recensedSprites[194]++;
							recensedSprites[195]++;
							recensedSprites[196]++;
							recensedSprites[132]++;
							recensedSprites[133]++;
						break;

						case 197:
							sprite[k].speed=0.0125;
							sprite[k].health=20*diff;
							sprite[k].discovered=0;
							recensedSprites[198]++;
							recensedSprites[199]++;
							recensedSprites[200]++;
							recensedSprites[201]++;
							recensedSprites[130]++;
							recensedSprites[132]++;
							recensedSprites[133]++;
						break;

						case 202:
							sprite[k].speed=0.025;
							sprite[k].health=38*diff;
							sprite[k].discovered=0;
							recensedSprites[203]++;
							recensedSprites[204]++;
							recensedSprites[205]++;
							recensedSprites[206]++;
							recensedSprites[130]++;
							recensedSprites[132]++;
							recensedSprites[133]++;
							recensedSprites[134]++;
						break;

						case 207:
							sprite[k].speed=0.015;
							sprite[k].wokenUp=0;
							sprite[k].stunned=0;
							sprite[k].health=700*diff;
							sprite[k].discovered=0;
							recensedSprites[208]++;
							recensedSprites[209]++;
							recensedSprites[210]++;
							recensedSprites[211]++;
							recensedSprites[138]++;
						break;
					}
				}


				recensedSprites[sprite[k].texture]++;
				k++;
				if (k==MAXSPRITES)
				{
					i=mapWidth+1;
					j=mapHeight+1;
				}
			}
		}
	}

	for (i=0; i<mapWidth; i++)
	{
		for (j=0; j<mapHeight; j++)
		{
			if (worldMap[i][j] > 1)
			{
				recensedTextures[worldMap[i][j]-1]++;

				if (worldMap[i][j] == 11) recensedTextures[11]=1;
				if (worldMap[i][j] == 19) recensedTextures[19]=1;
			}

			if ((worldMap[i][j] == 9) || (worldMap[i][j] == 10))
			{
				worldVendings[i][j]=random(8)+1;
			}

			if ((worldMap[i][j] == 18) || (worldMap[i][j] == 42) || (worldMap[i][j] == 43) || (worldMap[i][j] == 44))
			{
				worldDoors[i][j]=worldMap[i][j];
			}
		}
	}


	return k;
}

void center(int y, const char *text, int color)
{
	int k;

	oslSetTextColor(color);
	k = oslGetStringWidth(text);
	oslDrawString((480 - k)/2, y, text);
}

void cleanbuffer()
{
	oslDisableTransparentColor();
	oslStartDrawing();
    oslDrawFillRect(0,0,480,272, RGB(255,0,255));
    oslEndDrawing();
    oslSetTransparentColor(RGB(255,0,255));
}

void cleanbuffer2(int color)
{
	oslStartDrawing();
    oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
    oslDrawFillRect(0,0,480,272, color);

    oslSetTransparentColor(RGB(255,0,255));
}

void frame_debug(int frame)
{
	char buffer[20];
	OSL_FONT *oldFont = osl_curFont;
	oslSetFont(fonts[0]);

	oslSetTransparentColor(RGB(255,0,255));
	oslSetBkColor(RGB(255,0,255));
	oslSetTextColor(RGB(255, 255, 0));

	sprintf(buffer,"%d FPS",frame);

	oslDrawString(0, 0, buffer);
	oslSetFont(oldFont);
}

void fadein(OSL_IMAGE *image)
{
	int i;
	OSL_IMAGE *temp;

	temp=oslCreateImage(480, 272, OSL_IN_RAM, OSL_PF_5551);
	oslCopyImageTo(temp, image);

	for (i=0; i<400; i++)
	{
		    oslStartDrawing();
		    oslSetDrawBuffer(OSL_SECONDARY_BUFFER);
		    oslSetAlpha(OSL_FX_ALPHA,i/2);
		    oslDrawFillRect(0,0,480,272, RGB(0,0,0));
		    oslEndDrawing();
		    oslWaitVSync();
	}

	oslSetAlpha(OSL_FX_DEFAULT,0);
	spr_draw(temp,0,0);
	oslSetDrawBuffer(OSL_DEFAULT_BUFFER);

	oslDeleteImage(temp);
}

void fadeout(OSL_COLOR u)
{
	int i;
	for (i=0; i<80; i++)
	{
		    oslStartDrawing();
			oslSetDrawBuffer(OSL_SECONDARY_BUFFER);
			oslSetAlpha(OSL_FX_ALPHA,i*2);
			oslDrawFillRect(0,0,480,272, u);
		    oslEndDrawing();
		    oslWaitVSync();
	}
	oslSetAlpha(OSL_FX_DEFAULT,0);
	oslStartDrawing();
	oslDrawFillRect(0,0,480,272, u);
	oslEndDrawing();
	oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
}

char *sub_str(const char *s, unsigned int end)
{
	  if (s == 0 || strlen(s) == 0 || strlen(s) < 0 || strlen(s) < (end))
	    return 0;

	  return strndup(s, end);
}

void amigatext(const char *arg, int x, int y, OSL_IMAGE *amigafont, int width, int height)
{
	int i, l=strlen(arg), tx=x, placex=(amigafont -> sizeX)/width;
	int k;

	if (x==999)
	{
		k=l*width;
		tx=(480-k)/2;
	}

	for(i=0; i<l; i++)
	{
		if (arg[i] <= 'Z')
		{
			oslSetImageTileSize(amigafont, ((arg[i]-32)%placex)*width, ((arg[i]-32)/placex)*height, width, height);
			spr_draw(amigafont, tx, y);
		}

		tx += width;
	}
}

void loadLevel(int levelno)
{
	char path_buffer[50];
	int j[3];

	SceUID checkfile;
	sprintf(path_buffer, "./lvls/l%d.cgpm", levelno);
	if (levelno != -2) checkfile = sceIoOpen(path_buffer, PSP_O_RDONLY, 0777); else checkfile = sceIoOpen("./lvls/credits.cgpm", PSP_O_RDONLY, 0777);

	if (checkfile < 0)
	{
		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(255, 0, 0));
		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();
		oslQuit();
	}

	sceIoRead(checkfile, worldMap, sizeof(worldMap));
	sceIoRead(checkfile, worldPushable, sizeof(worldPushable));
	sceIoRead(checkfile, worldSprites, sizeof(worldSprites));

	sceIoRead(checkfile, floor_color, sizeof(floor_color));
	sceIoRead(checkfile, ceiling_color, sizeof(ceiling_color));

	sceIoRead(checkfile, j, sizeof(j));

	sceIoRead(checkfile, worldDiffs, sizeof(worldDiffs));

	startPosX=j[0];
	startPosY=j[1];
	startAngle=j[2];

	sceIoClose(checkfile);
}

int loadLevel_UI()
{
	int levelno=1, lvlmax=0, chl=1, chosen=0;
	char path_buffer[50];
	const char *lt="<-", *gt="->";
	SceUID checkfile=1;

	while (checkfile >= 0)
	{
		sprintf(path_buffer, "./lvls/l%d.cgpm", levelno);
		checkfile = sceIoOpen(path_buffer, PSP_O_RDONLY, 0777);

		if (checkfile < 0)
		{
			if (levelno == 1) return -1; else lvlmax=levelno;
		}
		else
		{
			levelno++;
		}

		sceIoClose(checkfile);
	}

	while (!chosen)
	{
		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));

		oslDrawGradientRect(0, 136, 480, 272, RGB(0, 0, 0), RGB(0, 0, 0), RGB(floor_color[0], floor_color[1], floor_color[2]), RGB(floor_color[0], floor_color[1], floor_color[2])); //RGB(108, 92, 80), RGB(108, 92, 80));
		oslDrawGradientRect(0, 0, 480, 136, RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]), RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]), RGB(0, 0, 0), RGB(0, 0, 0));

		center(120, "Which level?", RGB(255,255,255));
		oslSetFont(fonts[2]);
		sprintf(path_buffer, "%s %d %s", (chl>1)?lt:"", chl, (chl<lvlmax-1)?gt:"" );
		oslSetFont(fonts[0]);
		center(136, path_buffer, RGB(255,255,0));

		oslDrawString(0, 258, "LEFT or RIGHT to select, O or X to validate, TRIANGLE to cancel");

		oslEndDrawing();
		oslSwapBuffers();

		oslWaitVSync();

		oslReadKeys();

		if (osl_keys->pressed.triangle)
		{
			return -1;
		}

		if ((osl_keys->pressed.left) && (chl > 1)) chl--;
		if ((osl_keys->pressed.right) && (chl < lvlmax-1)) chl++;

		if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
		{
			chosen=1;
		}
	}

	oslSetTextColor(RGB(255, 255, 255));
	return chl;
}

int saveLevel()
{
	int levelno=1, j[3]={startPosX, startPosY, startAngle}, k;
	char path_buffer[50];
	SceUID checkfile=1;

	while (checkfile >= 0)
	{
		sprintf(path_buffer, "./lvls/l%d.cgpm", levelno);
		checkfile = sceIoOpen(path_buffer, PSP_O_RDONLY, 0777);
		sceIoClose(checkfile);
		levelno++;
	}

	checkfile = sceIoOpen(path_buffer, PSP_O_WRONLY|PSP_O_CREAT, 0777);

	k=sceIoWrite(checkfile, worldMap, sizeof(worldMap));
	if (!k) return -1;

	k=sceIoWrite(checkfile, worldPushable, sizeof(worldPushable));
	if (!k) return -1;

	k=sceIoWrite(checkfile, worldSprites, sizeof(worldSprites));
	if (!k) return -1;

	k=sceIoWrite(checkfile, floor_color, sizeof(floor_color));
	if (!k) return -1;

	k=sceIoWrite(checkfile, ceiling_color, sizeof(ceiling_color));
	if (!k) return -1;

	k=sceIoWrite(checkfile, j, sizeof(j));
	if (!k) return -1;

	k=sceIoWrite(checkfile, worldDiffs, sizeof(worldDiffs));
	if (!k) return -1;

	sceIoClose(checkfile);
	return levelno-1;
}

void saveLevel_numbered(int levelno)
{
	int j[3]={startPosX, startPosY, startAngle};
	char path_buffer[50];
	SceUID checkfile;

	sprintf(path_buffer, "./lvls/l%d.cgpm", levelno);
	checkfile = sceIoOpen(path_buffer, PSP_O_WRONLY, 0777);

	sceIoWrite(checkfile, worldMap, sizeof(worldMap));
	sceIoWrite(checkfile, worldPushable, sizeof(worldPushable));
	sceIoWrite(checkfile, worldSprites, sizeof(worldSprites));
	sceIoWrite(checkfile, floor_color, sizeof(floor_color));
	sceIoWrite(checkfile, ceiling_color, sizeof(ceiling_color));
	sceIoWrite(checkfile, j, sizeof(j));
	sceIoWrite(checkfile, worldDiffs, sizeof(worldDiffs));

	sceIoClose(checkfile);
}

void setColors(OSL_IMAGE *hand)
{
	int i, cht=0, chosen=0;
	int old_fc[3], old_cc[3];
	char bufr[4];
	const char *options[8]={"R","G","B","","","R","G","B"};

	for (i=0; i<3; i++)
	{
		old_fc[i]=floor_color[i];
		old_cc[i]=ceiling_color[i];
	}

	while (!chosen)
	{
		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));

		oslDrawGradientRect(0, 136, 480, 272, RGB(0, 0, 0), RGB(0, 0, 0), RGB(floor_color[0], floor_color[1], floor_color[2]), RGB(floor_color[0], floor_color[1], floor_color[2])); //RGB(108, 92, 80), RGB(108, 92, 80));
		oslDrawGradientRect(0, 0, 480, 136, RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]), RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]), RGB(0, 0, 0), RGB(0, 0, 0));

		for (i=0; i<8; i++)
		{
			if (i<3) sprintf(bufr, "%d", ceiling_color[i]);
			if (i>4) sprintf(bufr, "%d", floor_color[i-5]);
			oslDrawString(120, 36+i*24, options[i]);
			if ((i<3) || (i>4)) oslDrawString(320, 36+i*24, bufr);
		}

	  	spr_draw(hand, 80, 40+cht*24);

		oslDrawString(0, 258, "Press START to cancel");

		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();

		oslReadKeys();

		if ((osl_keys->pressed.up) && (cht > 0)) cht--;
		if ((osl_keys->pressed.down) && (cht < 7)) cht++;

		if (cht==3) cht=5; else if (cht==4) cht=2;

		if (osl_keys->held.left)
		{
			if (cht<3)
			{
				if (ceiling_color[cht] > 0) ceiling_color[cht]--;
			}
			else if (cht>4)
			{
				if (floor_color[cht-5] > 0) floor_color[cht-5]--;
			}
		}

		if (osl_keys->held.right)
		{
			if (cht<3)
			{
				if (ceiling_color[cht] < 255) ceiling_color[cht]++;
			}
			else if (cht>4)
			{
				if (floor_color[cht-5] < 255) floor_color[cht-5]++;
			}
		}

		if (osl_keys->pressed.start)
		{
			chosen=1;
			for (i=0; i<3; i++)
			{
				floor_color[i]=old_fc[i];
				ceiling_color[i]=old_cc[i];
			}
		}

		if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
		{
			chosen=1;
		}
	}
}

int selectSpr(int u, OSL_IMAGE *textures[256], int missingSprs[256])
{
	int i, chosen=0, cht=0, frame=0, page=0;

	while (!chosen)
	{
		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));
		for (i=0; i<64; i++)
		{
			if (!missingSprs[i+page*64]) spr_draw(textures[i+page*64], (i%15)*32, ((int)(i/15))*32);
		}
		oslDrawRect((cht%15)*32, (cht/15)*32, (cht%15)*32+32, (cht/15)*32+32, RGBA(255, 255, 255, (int)(128+127*vfpu_sinf(0.08*frame))));

		oslDrawString(0, 258, "Press TRIANGLE to cancel, R to switch to next bank of textures");

		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();

		frame++;

		oslReadKeys();


		if ((osl_keys->pressed.left) && (cht > 0)) cht--;
		if ((osl_keys->pressed.right) && (cht < 63)) cht++;
		if ((osl_keys->pressed.up) && (cht > 15)) cht-=15;
		if ((osl_keys->pressed.down) && (cht < 49)) cht+=15;

		if (osl_keys->pressed.R)
		{
			page++;
			page=page%4;
		}

		if (osl_keys->pressed.triangle) chosen=1;

		if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
		{
			if ((!missingSprs[cht+page*64]) && (cht+page*64 > 0))
			{
				chosen=1;
				u=cht+1+page*64;
			}
		}
	}

	if (!u) u=1;

	return u;
}


int selectTex(int u, OSL_IMAGE *textures[256], int missingTexs[256])
{
	int i, chosen=0, cht=0, frame=0, page=0;

	while (!chosen)
	{
		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));
		for (i=0; i<64; i++)
		{
			if (!missingTexs[i+page*64]) spr_draw(textures[i+page*64], (i%15)*32, ((int)(i/15))*32);
		}
		oslDrawRect((cht%15)*32, (cht/15)*32, (cht%15)*32+32, (cht/15)*32+32, RGBA(255, 255, 255, (int)(128+127*vfpu_sinf(0.08*frame))));

		oslDrawString(0, 258, "Press TRIANGLE to cancel, R to switch to next bank of textures");

		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();

		frame++;

		oslReadKeys();


		if ((osl_keys->pressed.left) && (cht > 0)) cht--;
		if ((osl_keys->pressed.right) && (cht < 63)) cht++;
		if ((osl_keys->pressed.up) && (cht > 15)) cht-=15;
		if ((osl_keys->pressed.down) && (cht < 49)) cht+=15;

		if (osl_keys->pressed.R)
		{
			page++;
			page=page%4;
		}

		if (osl_keys->pressed.triangle) chosen=1;

		if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
		{
			if ((!missingTexs[cht+page*64]) && (cht+page*64 > 0))
			{
				chosen=1;
				u=cht+1+page*64;
			}
		}
	}

	return u;
}

void lvmainmenu(int chm, OSL_IMAGE *hand)
{
	short i;
	const char *options[9]={"SELECT TEXTURE…", "SELECT SPRITE…", "SET FLOOR AND CEILING COLORS…", "TOGGLE DIFFICULTY SETTINGS", "LOAD LEVEL…", "SAVE AS NEW LEVEL", "OVERWRITE AN EXISTING LEVEL…", "NUKE THE LEVEL!", "QUIT TO MAIN MENU"};

  	oslDrawFillRect(0, 0, 480, 272, RGBA(0, 0, 0, 128));
  	spr_draw(hand, 80, 28+chm*24);

  	for (i=0; i<9; i++)
  	{
  		oslDrawString(120, 24+i*24, options[i]);
  	}
}

void level_editor(short keepit)
{
	int i, j, k, l, u, quit=0, camX=0, camY=0, mouseX=0, mouseY=0, tool=0, coeff, currentTex=2, currentSpr=129, menumode=0, chm=0, bottomTextX=480, w, messSaved=0, lvlSaved=0, diffmode=0;

	SceUID checkfile;
	OSL_IMAGE *cursor, *pushables, *hand, *greenlight, *anglestart;
	OSL_IMAGE *textures[256];
	OSL_IMAGE *sprs[256];
	int missingTexs[256], missingSprs[256], mapDrawn=0;


	const char *bottomText = "Welcome to the COGEEP TECH ENGINE level editor v1.00. Use the analog nub to move the cursor. Press O for drawing a wall, X for erasing underneath the cursor, TRIANGLE for drawing a sprite, SQUARE to set a pushable wall (repeated presses sets the direction), L to set the starting position (repeated presses on it sets the starting angle), START for main menu.";
	char path_buffer[50];
	char ram_avail[16];
	char a[3];

	oslSetTransparentColor(RGB(255,0,255));
	oslSetBkColor(RGB(255,0,255));
	oslSetAlpha(OSL_FX_DEFAULT, 0);

	w = oslGetStringWidth(bottomText);

	if (!keepit)
	{
		for (i=0; i<mapWidth; i++)
		{
			for (j=0; j<mapHeight; j++)
			{
				worldMap[i][j]=0;
				worldPushable[i][j]=0;
				worldSprites[i][j]=0;
			}
		}
	}

	for (i=0; i<mapWidth; i++)
	{
		worldMap[0][i]=2;
		worldMap[mapHeight-1][i]=2;
	}

	for (i=0; i<mapHeight; i++)
	{
		worldMap[i][0]=2;
		worldMap[i][mapWidth-1]=2;
	}

	cursor = oslLoadImageFilePNG("./lved/cursors.png", OSL_IN_RAM, OSL_PF_8888);
	pushables = oslLoadImageFilePNG("./lved/pushables.png", OSL_IN_RAM, OSL_PF_8888);
	hand = oslLoadImageFilePNG("./gfx/hand.png", OSL_IN_RAM, OSL_PF_5551);
	greenlight = oslLoadImageFilePNG("./lved/greenlight.png", OSL_IN_RAM, OSL_PF_8888);
	anglestart = oslLoadImageFilePNG("./lved/anglestart.png", OSL_IN_RAM, OSL_PF_8888);

	oslImageSetRotCenter(anglestart);
	anglestart -> angle = startAngle;

	for (i=0; i<256; i++)
	{
		missingTexs[i]=0;

		sprintf(path_buffer, "./gfx/texs/t%d.png", i);
		checkfile = sceIoOpen(path_buffer, PSP_O_RDONLY, 0777);

		oslStartDrawing();
		oslSetTextColor(RGB(255, 255, 0));
		oslDrawFillRect(0, 0, 480, 272, RGB(128,128,128));
		oslDrawString(0, 0, "Checking file:");
		oslDrawString(0, 8, path_buffer);
		sprintf(ram_avail,"%d bytes remaining", (int)oslGetRamStatus().maxAvailable);
		oslDrawString(0, 24, ram_avail);
		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();

		if (checkfile < 0)
		{
			missingTexs[i] = 1;
		}
		else
		{
			sprintf(path_buffer, "./gfx/texs/t%d.png", i);
			textures[i] = oslLoadImageFilePNG(path_buffer, OSL_IN_RAM, OSL_PF_5551);

			if (textures[i] -> sizeY > textures[i] -> sizeX) oslSetImageTileSize(textures[i], 0, 0, textures[i] -> sizeX, textures[i] -> sizeX); //keeping the first frame of animation of a tile only

			textures[i] -> stretchX = 32;
			textures[i] -> stretchY = 32;
		}

		sceIoClose(checkfile);
	}

	for (i=0; i<256; i++)
	{
		missingSprs[i]=0;

		sprintf(path_buffer, "./gfx/sprs/s%d.png", i);
		checkfile = sceIoOpen(path_buffer, PSP_O_RDONLY, 0777);

		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(128,128,128));
		oslDrawString(0, 0, "Checking file:");
		oslDrawString(0, 8, path_buffer);
		sprintf(ram_avail,"%d bytes remaining", (int)oslGetRamStatus().maxAvailable);
		oslDrawString(0, 24, ram_avail);
		oslEndDrawing();
		oslSwapBuffers();

		if (checkfile < 0)
		{
			missingSprs[i] = 1;
		}
		else
		{
			sprintf(path_buffer, "./gfx/sprs/s%d.png", i);
			sprs[i] = oslLoadImageFilePNG(path_buffer, OSL_IN_RAM, OSL_PF_5551);

			if (sprs[i] -> sizeY > sprs[i] -> sizeX) oslSetImageTileSize(sprs[i], 0, 0, sprs[i] -> sizeX, sprs[i] -> sizeX); //keeping the first frame of animation of a tile only

			sprs[i] -> stretchX = 32;
			sprs[i] -> stretchY = 32;
		}

		sceIoClose(checkfile);
	}

	oslSetTextColor(RGB(255, 255, 255));

	while (!quit)
	{
		oslSetImageTileSize(cursor, tool*16, 0, 16, 16);

		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(floor_color[0], floor_color[1], floor_color[2]));
		oslDrawFillRect(0, 256, 480, 272, RGB(0, 0, 0));
		oslSetTextColor(RGB(255, 255, 255));

		for (i=0; i<15; i++)
		{
			for(j=0; j<8; j++)
			{
				if (worldMap[j+camX][i+camY]>0) spr_draw(textures[(worldMap[j+camX][i+camY])-1], i*32, j*32);
				if (worldSprites[j+camX][i+camY]>0) spr_draw(sprs[(worldSprites[j+camX][i+camY])-1], i*32, j*32);

				oslSetImageTileSize(pushables, 32*worldPushable[j+camX][i+camY], 0, 32, 32);
				spr_draw(pushables, i*32, j*32);
				//spr_draw(textures[2], 0, 0);

				if ((j+camX == startPosX) && (i+camY == startPosY))
				{
					spr_draw(greenlight, i*32, j*32);
					spr_draw(anglestart, i*32+16, j*32+16);
				}

				if ((diffmode) && (worldSprites[j+camX][i+camY]-1 >= 192))
				{
					oslSetFont(fonts[1]);
					sprintf(a, "%d", worldDiffs[j+camX][i+camY]+1);
					oslDrawString(i*32+16, j*32+16, a);
					oslSetFont(fonts[0]);
				}
			}
		}

		if (!messSaved)
		{
			oslDrawString(bottomTextX, 258, bottomText);
			bottomTextX--;
		}
		else
		{
			messSaved--;
			if (lvlSaved != -1)
			{
				sprintf(path_buffer, "Level %d saved.", lvlSaved);
				center(258, path_buffer, RGB(255, 255, 0));
			}
			else
			{
				center(258, "ERROR WHILE WRITING ON THE MEMORY STICK!", RGB(255, 0, 0));
			}

		}


		if (bottomTextX == (-1*w)-16) bottomTextX=480;

		sprintf(a, "X: %d", camX+mouseY/32);
		oslDrawString(0, 0, a);
		sprintf(a, "Y: %d", camY+mouseX/32);
		oslDrawString(0, 8, a);

		if (diffmode) center(0, "SETTING DIFFICULTY LEVELS ON ENEMIES", RGB(255, 255, 255));



		oslDrawRect((mouseX-mouseX%32), (mouseY-mouseY%32), (mouseX-mouseX%32)+32, (mouseY-mouseY%32)+32, RGBA(255, 255, 255, (int)(128+127*vfpu_sinf(0.08*bottomTextX))));

		if (!menumode)
		{
			spr_draw(cursor, mouseX, mouseY);
		}
		else
		{
			lvmainmenu(chm, hand);
		}

		if (mapDrawn)
		{
			oslDrawFillRect(0, 0, 480, 272, RGB(22, 58, 68));

			for(u=0; u<256; u++)
			{
				if (!missingTexs[u])
				{
					textures[u] -> stretchX = 4;
					textures[u] -> stretchY = 4;
				}

				if (!missingSprs[u])
				{
					sprs[u] -> stretchX = 4;
					sprs[u] -> stretchY = 4;
				}

			}

			for (k=0; k<mapWidth; k++)
			{
				for (l=0; l<mapHeight; l++)
				{
					if (worldMap[l][k]>0)
					{
						spr_draw(textures[(worldMap[l][k])-1], 112+k*4, 8+l*4);
					}
					else
					{
						oslDrawFillRect(112+k*4,8+l*4,116+(k)*4,12+l*4, RGB(0, 0, 0));
					}

					if (worldSprites[l][k]>0)
					{
						spr_draw(sprs[(worldSprites[l][k])-1], 112+k*4, 8+l*4);
					}
				}
			}

			oslDrawRect(112+(camY)*4, 8+(camX)*4, 112+(15+camY)*4, 8+(8+camX)*4, RGBA(255, 255, 255, (int)(128+127*vfpu_sinf(0.08*bottomTextX))));

			for(u=0; u<256; u++)
			{
				if (!missingTexs[u])
				{
					textures[u] -> stretchX = 32;
					textures[u] -> stretchY = 32;
				}

				if (!missingSprs[u])
				{
					sprs[u] -> stretchX = 32;
					sprs[u] -> stretchY = 32;
				}
			}
		}

		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();

		oslReadKeys();

		if (osl_keys->pressed.start)
		{
			if (menumode) menumode=0; else menumode=1;
		}

		if (!menumode)
		{
			if (osl_keys->held.R)
			{
				mapDrawn=1;
			}
			else
			{
				mapDrawn=0;
			}

			if (osl_keys->pressed.L)
			{
				if (!worldMap[j+camX][i+camY])
				{
					if (((camX+mouseY/32) == startPosX) && ((camY+mouseX/32) == startPosY))
					{
						startAngle += 45;
						startAngle = startAngle%360;
						anglestart -> angle = startAngle;
					}

					startPosX=camX+mouseY/32;
					startPosY=camY+mouseX/32;
				}
			}

			if (osl_keys->held.cross)
			{
				tool=1;
				if ((camX+mouseY/32 > 0) && (camY+mouseX/32 > 0) && (camX+mouseY/32 < mapHeight) && (camY+mouseX/32 < mapWidth))
				{
					worldMap[camX+mouseY/32][camY+mouseX/32]=0;
				}
				else
				{
					worldMap[camX+mouseY/32][camY+mouseX/32]=17;
				}
				worldSprites[camX+mouseY/32][camY+mouseX/32]=0;
				worldPushable[camX+mouseY/32][camY+mouseX/32]=0;
			}
			else
			{
				tool=0;
			}

			if ((osl_keys->held.circle) && (!diffmode))
			{
				worldDiffs[camX+mouseY/32][camY+mouseX/32]=0;
				worldMap[camX+mouseY/32][camY+mouseX/32]=currentTex;
				worldSprites[camX+mouseY/32][camY+mouseX/32]=0;
			}

			if ((osl_keys->pressed.circle) && (diffmode) && (worldSprites[camX+mouseY/32][camY+mouseX/32]-1 >= 192))
			{
				worldDiffs[camX+mouseY/32][camY+mouseX/32]++;
				worldDiffs[camX+mouseY/32][camY+mouseX/32]=worldDiffs[camX+mouseY/32][camY+mouseX/32]%4;
			}

			if (osl_keys->held.triangle)
			{
				if ((camX+mouseY/32 > 0) && (camY+mouseX/32 > 0) && (camX+mouseY/32 < mapHeight) && (camY+mouseX/32 < mapWidth))
				{
					worldMap[camX+mouseY/32][camY+mouseX/32]=0;
					worldSprites[camX+mouseY/32][camY+mouseX/32]=currentSpr;
				}
			}

			if (osl_keys->pressed.square)
			{
				if (worldMap[camX+mouseY/32][camY+mouseX/32]==0)
				{
					worldMap[camX+mouseY/32][camY+mouseX/32]=currentTex;
					worldDiffs[camX+mouseY/32][camY+mouseX/32]=0;
				}

				if (worldSprites[camX+mouseY/32][camY+mouseX/32]!=0)
				{
					worldSprites[camX+mouseY/32][camY+mouseX/32]=0;
				}

				if ((camX+mouseY/32 >= 1) && (camY+mouseX/32 >= 1) && (camX+mouseY/32 <= mapHeight-2) && (camY+mouseX/32 <= mapWidth-2))
				{
					worldPushable[camX+mouseY/32][camY+mouseX/32]++;
					worldPushable[camX+mouseY/32][camY+mouseX/32] = worldPushable[camX+mouseY/32][camY+mouseX/32]%5;
				}

				if ((camX+mouseY/32 <= 1) && (worldPushable[camX+mouseY/32][camY+mouseX/32]==1))
				{
					worldPushable[camX+mouseY/32][camY+mouseX/32]=2;
				}

				if ((camY+mouseX/32 <= 1) && (worldPushable[camX+mouseY/32][camY+mouseX/32]==4))
				{
					worldPushable[camX+mouseY/32][camY+mouseX/32]=0;
				}

				if ((camY+mouseX/32 >= mapWidth-2) && (worldPushable[camX+mouseY/32][camY+mouseX/32]==2))
				{
					worldPushable[camX+mouseY/32][camY+mouseX/32]=3;
				}

				if ((camX+mouseY/32 >= mapHeight-2) && (worldPushable[camX+mouseY/32][camY+mouseX/32]==3))
				{
					worldPushable[camX+mouseY/32][camY+mouseX/32]=4;
					if (camY+mouseX/32 <= 1) worldPushable[camX+mouseY/32][camY+mouseX/32]=0;
				}
			}

			if ((osl_keys->pressed.left) && (camY > 0)) camY--;
			if ((osl_keys->pressed.right) && (camY+15 < mapWidth)) camY++;
			if ((osl_keys->pressed.up) && (camX > 0)) camX--;
			if ((osl_keys->pressed.down) && (camX+8 < mapHeight)) camX++;

			if (!mapDrawn)
			{
				if ((osl_pad.analogY < -16))
				{
				  coeff=abs(osl_pad.analogY)/16;
				  mouseY -= coeff;
				  if (mouseY < 0) mouseY=0;
				}

				if ((osl_pad.analogY > 16))
				{
				  coeff=abs(osl_pad.analogY)/16;
				  mouseY += coeff;
				  if (mouseY > 240) mouseY=240;
				}

				if ((osl_pad.analogX > 16))
				{
				  coeff=abs(osl_pad.analogX)/16;
				  mouseX += coeff;
				  if (mouseX > 464) mouseX=464;
				}

				if ((osl_pad.analogX < -16))
				{
				  coeff=abs(osl_pad.analogX)/16;
				  mouseX -= coeff;
				  if (mouseX < 0) mouseX=0;
			}
			}
		}
		else
		{
			if ((osl_keys->pressed.up) && (chm > 0)) chm--;
			if ((osl_keys->pressed.down) && (chm < 8)) chm++;

			if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
			{
				switch(chm)
				{
					case 0:
						currentTex=selectTex(currentTex, textures, missingTexs);
					break;

					case 1:
						currentSpr=selectSpr(currentSpr, sprs, missingSprs);
						if ((currentSpr >= 199) && (currentSpr <= 201)) currentSpr=198;
						else if ((currentSpr >= 194) && (currentSpr <= 196)) currentSpr=193;
						else if ((currentSpr >= 204) && (currentSpr <= 206)) currentSpr=203;
						else if ((currentSpr >= 209) && (currentSpr <= 211)) currentSpr=208;
					break;

					case 2:
						setColors(hand);
					break;

					case 3:
						if (!diffmode) diffmode=1; else diffmode=0;
					break;

					case 4:
						i=loadLevel_UI();
						if (i != -1)
						{
							loadLevel(i);
							anglestart -> angle = startAngle;
						}
					break;

					case 5:
						lvlSaved=saveLevel();
						messSaved=240;
					break;

					case 6:
						lvlSaved=loadLevel_UI();
						if (lvlSaved != -1)	saveLevel_numbered(lvlSaved);
						messSaved=240;
					break;

					case 7:
						for (i=0; i<mapWidth; i++)
						{
							for (j=0; j<mapHeight; j++)
							{
									worldMap[i][j]=0;
									worldPushable[i][j]=0;
									worldSprites[i][j]=0;
							}
						}

						for (i=0; i<mapWidth; i++)
						{
							worldMap[0][i]=2;
							worldMap[mapHeight-1][i]=2;
						}

						for (i=0; i<mapHeight; i++)
						{
							worldMap[i][0]=2;
							worldMap[i][mapWidth-1]=2;
						}
					break;

					case 8:
						quit=1;
					break;
				}
			}
		}
	}

	for (i=0; i<128; i++)
	{
		if (!missingTexs[i]) oslDeleteImage(textures[i]);
	}

	for (i=0; i<256; i++)
	{
		if (!missingSprs[i]) oslDeleteImage(sprs[i]);
	}

	oslDeleteImage(cursor);
	oslDeleteImage(hand);
	oslDeleteImage(pushables);
	oslDeleteImage(greenlight);
	oslDeleteImage(anglestart);

}

void mainmenu(int quality, int swidth, int sheight, int keepratio, int sol, int ceiling, int bilifilt, int quit, int music_volume, int chm, OSL_IMAGE *hand)
{
	short i;
	const char *options[9]={"SCREEN WIDTH", "SCREEN HEIGHT", "KEEP SCREEN RATIO", "TEXTURE QUALITY", "ADAPTIVE QUALITY", "VSYNC", "AMBIENT LIGHTNING", "MUSIC VOLUME", "QUIT"};
	const char *qualnames[4]={"HIGH", "MEDIUM", "LOW", "EYE-BLEEDING"};
	const char *ambientlights[3]={"DARK PATHWAYS", "UNSECURE CITY", "NONE"};

	char sizes[2][4];
	char vol[4];

	oslSetTransparentColor(RGB(255,0,255));
	oslSetBkColor(RGB(255,0,255));
	oslSetTextColor(RGB(255, 255, 255));

  	oslDrawFillRect(0, 0, 480, 272, RGBA(0, 0, 0, 128));
  	spr_draw(hand, 80, 40+chm*24);

  	sprintf(sizes[0], "%d", swidth);
  	sprintf(sizes[1], "%d", sheight);

  	for (i=0; i<9; i++)
  	{
  		oslDrawString(120, 36+i*24, options[i]);
  	}

  	if (keepratio == 0)
  	{
  		oslSetTextColor(RGB(255, 255, 255));
  		oslDrawString(120, 60, options[1]);
  		oslDrawString(320, 60, sizes[1]);
  		oslDrawString(320, 84, "OFF");
  	}
  	else
  	{
  		oslSetTextColor(RGB(96, 96, 96));
  		oslDrawString(120, 60, options[1]);
  		oslDrawString(320, 60, sizes[1]);
  		oslSetTextColor(RGB(255, 255, 255));
  		oslDrawString(320, 84, "ON");
  	}

  	oslDrawString(320, 108, qualnames[quality-1]);
  	oslDrawString(320, 180, ambientlights[bilifilt]);
  	oslDrawString(320, 36, sizes[0]);

  	sprintf(vol, "%d", music_volume);
  	oslDrawString(320, 204, vol);


  	if (sol == 1)
  	{
  		oslDrawString(320, 132, "ON");
  	}
  	else
  	{
  		oslDrawString(320, 132, "OFF");
  	}

  	if (ceiling == 1)
  	{
  		oslDrawString(320, 156, "ON");
  	}
  	else
  	{
  		oslDrawString(320, 156, "OFF");
  	}





}

void rndsft()
{
		int frame=0;
		OSL_IMAGE *rndsft;
		OSL_SOUND *rndtheme;

		rndsft = oslLoadImageFilePNG("./gfx/rndsft.png",OSL_IN_RAM, OSL_PF_5551);
		rndtheme = oslLoadSoundFileMOD("./mzx/rndsft.xm", OSL_FMT_NONE);

		oslSetFont(fonts[2]);
		oslSetImageRotCenter(rndsft);

		oslPlaySound(rndtheme, 5);

		while(frame<600)
		{
			oslStartDrawing();
			oslDrawFillRect(0,0,480,272, RGB(0,0,0));

			if (frame >= 181)
			{
				if (frame-180 < 35)
				{
					oslSetAlpha(OSL_FX_ALPHA, (frame-180)*7);
					rndsft -> angle = -1*(frame-215);
					oslSetImageTile(rndsft,0,0,282,frame-180);
				}
				else
				{
					rndsft -> angle = 0;
					oslSetAlpha(OSL_FX_DEFAULT,0);
					oslSetImageTile(rndsft,0,0,282,35);
				}
				spr_draw(rndsft,240,138);
				center(160, "STUDIO", RGB(255, 255, 255));
			}
			oslEndDrawing();
			oslSwapBuffers();
			oslWaitVSync();
			frame++;

			if ((oslKbhit()) && (frame<590)) frame=590;
		}

		oslStopSound(rndtheme);
		oslDeleteSound(rndtheme);
		oslDeleteImage(rndsft);
		fadeout(RGB(0,0,0));
}

void cutscene_text(int y, const char *text, short speed)
{
	char *subtext;
	int k, l, frame=0, substr=1;
	OSL_FONT *oldFont = osl_curFont;

	oslSetFont(fonts[1]);
	oslSetTextColor(RGB(255, 255, 255));
	k = oslGetStringWidth(text);
	l = strlen(text);


	if (speed < 2) speed=2;

	while (substr<=l)
	{
		if (!(frame%speed))
		{
			subtext=sub_str(text, substr);
			oslDrawString((480 - k)/2, y, subtext);
			substr++;
			free(subtext);
		}
		frame++;
		oslWaitVSync();
	}


	oslSetFont(oldFont);
}

void drawHealth(int health, int ammo, int coins, int armor, OSL_IMAGE *digits, OSL_IMAGE *bullet, OSL_IMAGE *coin, int fps, int keys[3], OSL_IMAGE *minikeys, OSL_IMAGE *armor_icon)
{
	int i, tx=20;
	char str_health[10];
	oslSetImageTileSize(digits,80,0,8,8);
	oslSetImageRotCenter(digits);
	oslSetImageRotCenter(bullet);
	oslSetImageRotCenter(coin);
	spr_draw(digits,10,264);
	spr_draw(bullet,470,260);
	spr_draw(coin,470,8);

	if ((fps%60) > 30)
	{
		oslSetAlpha(OSL_FX_ALPHA, 180-((fps%60)*3));
		digits -> stretchX = 60-(fps%60);
		digits -> stretchY = 60-(fps%60);
		spr_draw(digits,10,264);
	}

	digits -> stretchX = 8;
	digits -> stretchY = 8;

	oslSetAlpha(OSL_FX_DEFAULT, 0);

	digits -> centerX = 0;
	digits -> centerY = 0;

	sprintf(str_health, "%d", health);

	for (i=0; i<strlen(str_health); i++)
	{
		oslSetImageTileSize(digits, (str_health[i]-32)*8, 0, 8, 8);
		spr_draw(digits, tx, 260);
		tx+=8;
	}

	if (armor)
	{
		tx=20;

		spr_draw(armor_icon, 7, 248);
		sprintf(str_health, "%d", armor);

		for (i=0; i<strlen(str_health); i++)
		{
			oslSetImageTileSize(digits, (str_health[i]-32)*8, 0, 8, 8);
			spr_draw(digits, tx, 248);
			tx+=8;
		}
	}

	sprintf(str_health, "%d", ammo);
	tx = 460 - strlen(str_health)*8;

	for (i=0; i<strlen(str_health); i++)
	{
		oslSetImageTileSize(digits, (str_health[i]-32)*8, 0, 8, 8);
		spr_draw(digits, tx, 260);
		tx+=8;
	}

	sprintf(str_health, "%d", coins);
	tx = 460 - strlen(str_health)*8;

	for (i=0; i<strlen(str_health); i++)
	{
		oslSetImageTileSize(digits, (str_health[i]-32)*8, 0, 8, 8);
		spr_draw(digits, tx, 4);
		tx+=8;
	}

	for (i=0; i<3; i++)
	{
		if (keys[i])
		{
			oslSetImageTileSize(minikeys, i*8, 0, 8, 16);
			spr_draw(minikeys, i*8+4, 4);
		}
	}

	oslDrawString(232, 130, "+");
}

//sort algorithm
void combSort(int* order, float* dist, int amount)
{
  int gap = amount;
  int swapped = 0;
  int tempvar, i, j;
  float tempvarF;

  while(gap > 1 || swapped)
  {
    //shrink factor 1.3
    gap = (gap * 10) / 13;
    if(gap == 9 || gap == 10) gap = 11;
    if (gap < 1) gap = 1;
    swapped = 0;
    for (i = 0; i < amount - gap; i++)
    {
      j = i + gap;
      if (dist[i] < dist[j])
      {
    	  tempvarF=dist[i];
    	  dist[i]=dist[j];
    	  dist[j]=tempvarF;

    	  tempvar=order[i];
    	  order[i]=order[j];
    	  order[j]=tempvar;

        swapped = 1;
      }
    }
  }
}

void selSort(int* order, float* dist, int amount)
{
    int i, j, m, t;
    float tempvarF;

    for (i = 0; i < amount; i++) {
        for (j = i, m = i; j < amount; j++)
        {
            if (dist[j] > dist[m]) m = j;
        }

        t = order[i];
        order[i] = order[m];
        order[m] = t;

		tempvarF=dist[i];
		dist[i]=dist[m];
		dist[m]=tempvarF;
    }

}



void quickSort(int* order, float* dist, int debut, int fin)
{
    int gauche = debut-1;
    int droite = fin+1;
    int t;
    float pivot = dist[debut];
    int tempvarF;

    /* Si le tableau est de longueur nulle, il n'y a rien à faire. */
    if(debut >= fin)
        return;

    /* Sinon, on parcourt le tableau, une fois de droite à gauche, et une
       autre de gauche à droite, à la recherche d'éléments mal placés,
       que l'on permute. Si les deux parcours se croisent, on arrête. */
    while(1)
    {
        do droite--; while((dist[droite] < pivot) && (droite >= debut));
        do gauche++; while(dist[gauche] > pivot);

        if(gauche < droite)
        {
            t = order[gauche];
            order[gauche] = order[droite];
            order[droite] = t;

    		tempvarF=dist[gauche];
    		dist[gauche]=dist[droite];
    		dist[droite]=tempvarF;
        }
        else break;
    }

    /* Maintenant, tous les éléments inférieurs au pivot sont avant ceux
       supérieurs au pivot. On a donc deux groupes de cases à trier. On utilise
       pour cela... la méthode quickSort elle-même ! */
    quickSort(order, dist, debut, droite);
    quickSort(order, dist, droite+1, fin);
}

int sign(x)
{
	if (x >= 0) return 1; else return -1;
}

void siftDown(int* a, float* dist, int start, int end)
{
    int root = start, t;
    int tempvarF;

		while ( root*2+1 < end ) {
			int child = 2*root + 1;
			if ((child + 1 < end) && (dist[child] > dist[child+1])) {
				child += 1;
			}
			if ((dist[root] > dist[child])) {
				t = a[child];
				a[child] = a[root];
				a[root] = t;

				tempvarF=dist[child];
				dist[child]=dist[root];
				dist[root]=tempvarF;
				root = child;
			}
			else
				return;
		}
}

void heapSort(int* a, float* dist, int count)
{
    int start, end;
    int t;
    float tempvarF;

    /* heapify */
    for (start = (count-2)/2; start >=0; start--) {
        siftDown(a, dist, start, count);
    }

    for (end=count-1; end > 0; end--) {
        t = a[end];
        a[end] = a[0];
        a[0] = t;

		tempvarF=dist[end];
		dist[end]=dist[0];
		dist[0]=tempvarF;

        siftDown(a, dist, 0, end);
    }
}

void introSort(int* a, float* dist, int count)
{
	int i, sorted=1, depth;

	while (sorted)
	{
		for (i=0; i<count-1; i++)
		{
			if (dist[i] < dist[i+1]) sorted=0;
		}

		if (i == count)
		{
			sorted=0;
		}
		else
		{
			depth=vfpu_logf(i)*2;

			if (depth < 1)
			{
				heapSort(a, dist, i);
			}
			else
			{
				quickSort(a, dist, 0, i);
			}
		}
	}

}
void dead(int frame, OSL_COLOR color)
{
	oslDrawFillRect(0, 0, 480, frame, color);
}


inline float pspFpuAbs(float fs)
{
	/*union		//This could be slower than the real deal absf() due to mem access?
        {
        int tmp;
        float fpv;
        } uni;
	uni.fpv = fs;
	uni.tmp = uni.tmp & 0x7FFFFFFF;
	return(uni.fpv);*/

    float result;
		__asm__ volatile (
			"mtv      %1, S000\n"
			"vabs.s   S000, S000\n"
			"mfv      %0, S000\n"
		: "=r"(result) : "r"(fs));
		return result;
}

inline int pspFpuFloor(float fs)
{
	return (__builtin_allegrex_floor_w_s(fs));
}

int isNotLight(int kul)
{
	return ((kul != 165) && (kul != 166) && (kul != 167) && (kul != 170) && (kul != 21) && (kul != 44) && (kul != 173));
}

int isFiring(int wkn, int tex)
{
	return (((wkn%32 == 12) && (tex == 198)) || ((wkn%8 == 4) && (tex == 203)) || (tex == 208));
}

int game(int *options, int angle, int sPosX, int sPosY, int floor_color[3], int ceiling_color[3], const char *music, int isCredits, Sprite sprite[MAXSPRITES], int diff)
{
	  int deathcause=0, deathFrame=0, thirst=0, frameshot=0, goggles=0, nbEnemies=0, nbKilled=0, nbSecrets=0, nbPushed=0;
	  int doorkeys[3]={0, 0, 0}, cspr;

	  int mapMode=0;

	  int worldDiscovered[mapWidth][mapHeight];
	  int spriteDiscovered[mapWidth][mapHeight];

	  int sprChunk=0, qualityFrame=0;

	  //mainmenu(int quality, int swidth, int sheight, int keepratio, int sol, int ceiling, int bilifilt, int quit, int chm, OSL_IMAGE *hand)

	  unsigned long int frame=0;
	  int fogType=options[6], mindfuck=0, pickedup=0, messagepick=-1, respir=0, torchlight, k, l, doorTrans=0, movingTile=0, pushedTileX=0, pushedTileY=0, pushedTileDir=0, uTurn=0, weaponY=0;

	  int visibleSprite[MAXSPRITES], facingSprite=0, facingSpriteNumber=0, facingSide=0, nbSprites=0, skipframe=0, dark, i, y, x, quit=0, fps=0, fps_to_display=0, menumode=0, chm=0, sol=options[4], vsync=options[5], messagetime=0, messageno=-1;
	  char path_buffer[40];

	  int nbTex=0, nbSpr=0, nbTexL=0, nbSprL=0;

	  int animatedTexs[3][5] = {{-1, -1, -1, -1, -1},
			  	  	  	  	  	{11, 128, 6, 4, 0}};

	  int textureSpeed=1, foundAnimated=0, texNbFrames=1, texAnimatedSides=0;

	  int animatedSprs[12][4] = {{192, 64, 9, 4}, {193, 64, 9, 4}, {195, 64, 9, 4},
			  	  	  	  	  	 {197, 64, 9, 4}, {198, 64, 9, 4}, {200, 64, 9, 4},
			  	  	  	  	  	 {202, 64, 9, 4}, {203, 64, 4, 2}, {205, 64, 9, 4},
	  	  	  	  	  	  	  	 {207, 64, 9, 4}, {208, 64, 4, 2}, {210, 64, 9, 4}};
	  int spriteSpeed=1, sprNbFrames=1, spriteAnimHeight=0;


	  int drawStartX, drawStartY, drawEndX, drawEndY;

      int pspFpuFloorTexX, pspFpuFloorTexY, facingTexture=0, spritePosX, spritePosY;

      int messageno_s=-1, textureWidth, textureHeight, pspFpuFloortexWidth, pspFpuFloortexHeight, spriteHeight, spriteScreenX, spriteWidth, stripe, vMoveScreen;

      float bobbing=0.025, j;

      float distToSprite=256.0, spriteX, spriteY, invDet, transformX, transformY=0, coeff=0;
      float posX = sPosX+0.5;
      float posY = sPosY+0.5;

	  float dirX = -1.0, dirY = 0.0; //initial direction vector
	  float planeX = 0.0, planeY = 0.66; //the 2d raycaster version of camera plane

	  float pspFpuFloorXWall, pspFpuFloorYWall, distWall, distPlayer, currentDist, weight, currentpspFpuFloorX, currentpspFpuFloorY, distToFacingTex=300;

	  float oldDirX, oldPlaneX, moveSpeed, rotSpeed, cameraX, rayPosX, rayPosY, rayDirX=0, rayDirY=0, sideDistX=0.0, sideDistY=0.0, deltaDistX, deltaDistY, perpWallDist, wallX, frameTime;
	  int mapX=0, mapY=0, stepX, stepY, hit, side=0, lineHeight, drawStart, drawEnd, texX, quality=options[0], w=options[1], h=options[2], texNum;

	  int lowBoundsprChunk=0, hiBoundsprChunk=0;

	  float ZBuffer[485];

	  const char *responses[128];
	  const char *responses2[256];

	  const char *msgpicks[64] = {"YOU PICKED UP A MEDIKIT", "YOU PICKED UP A GREATER MEDIKIT", "YOU PICKED UP A CLIP", "YOU PICKED UP A BOX OF BULLETS",
	  	  	  	  	  	  	  	  "YOU PICKED UP 2 CREDITS", "YOU PICKED UP 1 CREDIT", "YOU PICKED AN ASSAULT RIFLE", "YOU FOUND THE CHAINGUN! MAKE SOME GIBS!",
	  	  	  	  	  	  	  	  "YOU PICKED UP THE BRONZE KEY", "YOU PICKED UP THE SILVER KEY", "YOU PICKED UP THE GOLD KEY",
	  	  	  	  	  	  	  	  "YOU ATE A SANDWICH FROM FRENCH RAIL COMPANY", "WINNERS SHOULDN'T DO DRUGS.", "YOU PICKED UP A BULLETPROOF VEST", "SUPERCHARGE!",
	  	  	  	  	  	  	  	  "YOU PICKED UP NIGHT VISION GOGGLES. LIGHTS ON!"};

	  const char *credits[4] = {"COGEEP Tech Engine - Copyleft 2015-2016 by 240-185", "MADE FOR", "AC 2016 WAS ORGANIZED BY", "Based on a raycasting engine by Lode VANDEVENNE"};

	  u32 tickResolution;
	  u64 fpsTickNow;
	  u64 fpsTickLast, fpsPreviousTick;

	  OSL_IMAGE *sfresh, *amiga, *weapons[4], *weapon_fire, *bullet, *sidedoor, *minikeys;
	  OSL_IMAGE *texture[256][2], *hand, *texpspFpuFloor, *sprs[256], *sky, *coin;
	  OSL_IMAGE *digits = oslLoadImageFilePNG("./gfx/hud_digits.png", OSL_IN_RAM, OSL_PF_5551), *armor_icon;
	  OSL_SOUND *wolfen, *uhcakip, *rumble, *enemy, *weapon_shoot, *shovel, *dying, *weapon_click, *load, *aah, *urdead, *endlevel, *knifing, *grunt, *shotgun;
	  OSL_SOUND *supercharge, *vomit, *coins_sound, *gulp, *machinegun, *got_mg, *got_sg, *huhaha, *seeknd, *b1_die, *b1_hurt, *boiling, *waiting, *door_open, *door_close, *worn_out;
	  OSL_COLOR shrooms=RGB(0, 0, 0);


	  sfresh = oslLoadImageFilePNG("./gfx/stay_fresh.png", OSL_IN_RAM, OSL_PF_5551);

		 oslStartDrawing();
		 oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));
		 spr_draw(sfresh, 120, 128);
		 center(200, "Loading common files…", RGB(255, 255, 255));
		 oslEndDrawing();
		 oslSwapBuffers();

	  waiting = oslLoadSoundFileWAV("./mzx/waiting.wav", OSL_FMT_NONE);

      oslSetSoundLoop(waiting, 1);
	  if (!isCredits) oslPlaySound(waiting, 0);

	  uhcakip = oslLoadSoundFileWAV("./sfx/uhcakip.wav", OSL_FMT_NONE);
	  rumble = oslLoadSoundFileWAV("./sfx/rumble.wav", OSL_FMT_NONE);
	  enemy = oslLoadSoundFileWAV("./sfx/enemy0_wokenup.wav", OSL_FMT_NONE);
	  weapon_shoot = oslLoadSoundFileWAV("./sfx/handgun_shot.wav", OSL_FMT_NONE);
	  weapon_click = oslLoadSoundFileWAV("./sfx/click.wav", OSL_FMT_NONE);
	  shovel = oslLoadSoundFileWAV("./sfx/shovel.wav", OSL_FMT_NONE);
	  dying = oslLoadSoundFileWAV("./sfx/dying.wav", OSL_FMT_NONE);
	  load = oslLoadSoundFileWAV("./sfx/load.wav", OSL_FMT_NONE);
	  aah = oslLoadSoundFileWAV("./sfx/aah.wav", OSL_FMT_NONE);
	  urdead = oslLoadSoundFileWAV("./sfx/urdead.wav", OSL_FMT_NONE);
	  endlevel = oslLoadSoundFileWAV("./sfx/endlevel.wav", OSL_FMT_NONE);
	  knifing = oslLoadSoundFileWAV("./sfx/knifing.wav", OSL_FMT_NONE);
	  grunt = oslLoadSoundFileWAV("./sfx/grunt.wav", OSL_FMT_NONE);
	  vomit = oslLoadSoundFileWAV("./sfx/vomit.wav", OSL_FMT_NONE);
	  coins_sound = oslLoadSoundFileWAV("./sfx/coins.wav", OSL_FMT_NONE);
	  gulp = oslLoadSoundFileWAV("./sfx/gulp.wav", OSL_FMT_NONE);
	  shotgun = oslLoadSoundFileWAV("./sfx/shotgun.wav", OSL_FMT_NONE);
	  machinegun = oslLoadSoundFileWAV("./sfx/machinegun.wav", OSL_FMT_NONE);
	  huhaha = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);
	  seeknd = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);
	  door_open = oslLoadSoundFileWAV("./sfx/door_open.wav", OSL_FMT_NONE);
	  door_close = oslLoadSoundFileWAV("./sfx/door_close.wav", OSL_FMT_NONE);
	  supercharge = oslLoadSoundFileWAV("./sfx/supercharge.wav", OSL_FMT_NONE);
	  worn_out = oslLoadSoundFileWAV("./sfx/worn_out.wav", OSL_FMT_NONE);



	  amiga = oslLoadImageFilePNG("./gfx/amiga_.png", OSL_IN_RAM, OSL_PF_5551);
	  sky = oslLoadImageFilePNG("./gfx/sky1.png", OSL_IN_RAM, OSL_PF_5551);
	  coin = oslLoadImageFilePNG("./gfx/coin.png", OSL_IN_RAM, OSL_PF_5551);
	  weapons[0] = oslLoadImageFilePNG("./gfx/handgun0.png", OSL_IN_RAM, OSL_PF_5551);
	  weapons[1] = oslLoadImageFilePNG("./gfx/handgun1.png", OSL_IN_RAM, OSL_PF_5551);
	  weapons[2] = oslLoadImageFilePNG("./gfx/handgun2.png", OSL_IN_RAM, OSL_PF_5551);
	  weapons[3] = oslLoadImageFilePNG("./gfx/handgun3.png", OSL_IN_RAM, OSL_PF_5551);
	  sidedoor = oslLoadImageFilePNG("./gfx/texs/sidedoor.png", OSL_IN_RAM, OSL_PF_5551);
	  minikeys = oslLoadImageFilePNG("./gfx/minikeys.png", OSL_IN_RAM, OSL_PF_8888);
	  armor_icon = oslLoadImageFilePNG("./gfx/armor.png", OSL_IN_RAM, OSL_PF_5551);


	  wolfen = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);

	  got_sg = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);
	  got_mg = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);

	  b1_die = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);
	  b1_hurt = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);

	  boiling = oslLoadSoundFileWAV("./sfx/dummy.wav", OSL_FMT_NONE);

	  weapon_fire = oslLoadImageFilePNG("./gfx/handgun_fire.png", OSL_IN_RAM, OSL_PF_5551);
	  bullet = oslLoadImageFilePNG("./gfx/bullet.png", OSL_IN_RAM, OSL_PF_8888);

	  i=strlen(music);

	  oslDeleteSound(wolfen);

	  if (music[i-1] == '3')
	  {
		  wolfen = oslLoadSoundFileMP3(music, OSL_FMT_STREAM);
		  wolfen -> volumeLeft = 163.84 * options[8];
		  wolfen -> volumeRight = 163.84 * options[8];
	  }
	  else if (music[i-1] == 'm')
	  {
		  wolfen = oslLoadSoundFileMOD(music, OSL_FMT_NONE);
		  wolfen -> volumeLeft = 163.84 * options[8];
		  wolfen -> volumeRight = 163.84 * options[8];
	  }

	  nbSprites=initBarrels(sprite, diff);

		for (k=0; k<mapWidth; k++)
		{
			for (l=0; l<mapHeight; l++)
			{
				worldDiscovered[k][l]=0;
				spriteDiscovered[k][l]=0;

				if (worldPushable[k][l])
				{
					nbSecrets++;
				}
			}
		}

	  texture[0][0] = oslLoadImageFilePNG("./gfx/texs/t0.png",OSL_IN_RAM, OSL_PF_5551);
	  texture[0][1] = oslLoadImageFilePNG("./gfx/texs/t0.png",OSL_IN_RAM, OSL_PF_5551);

		for (i=0; i<MAXSPRITES; i++)
		{
			visibleSprite[i]=0;
			if ((sprite[i].texture == 192) ||
				(sprite[i].texture == 197) ||
				(sprite[i].texture == 202) ||
				(sprite[i].texture == 207))
			{
				nbEnemies++;
			}
		}

	  for (i=1; i<256; i++) responses2[i]="";
	  responses2[1] = "YOU DON'T WEAR ANY COAT!";
	  responses2[2] = "THIS BARREL IS EMPTY";
	  responses2[3] = "IT'S NOT PEE PEE TIME!";
	  responses2[6] = "DON'T WORRY, HE WON'T HURT YOU.";
	  responses2[11] = "STILL NOT PEE PEE TIME.";
	  responses2[13] = "PURE GENUINE CHEAP PIECE OF FURNITURE!";


	  for (i=0; i<256; i++)
	  {
		  if (recensedTextures[i] > 0) nbTex++;
		  if (recensedSprites[i] > 0) nbSpr++;
	  }

	  for (i=1; i<256; i++)
	  {
		 oslStartDrawing();
		 oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));
		 if (!isCredits)
		 {
			 spr_draw(sfresh, 120, 128);
			 sprintf(path_buffer,"Textures loaded: %d %%",(int)((float)(nbTexL*100/nbTex)));
			 center(200, path_buffer, RGB(255, 255, 255));
		 }
		 oslEndDrawing();
		 oslSwapBuffers();

		 if (recensedTextures[i] > 0)
		 {
			sprintf(path_buffer,"./gfx/texs/t%d.png",i);
			texture[i][0] = oslLoadImageFilePNG(path_buffer,OSL_IN_RAM, OSL_PF_5551);
			sprintf(path_buffer,"./gfx/texs/t%ds.png",i);
			texture[i][1] = oslLoadImageFilePNG(path_buffer,OSL_IN_RAM, OSL_PF_5551);

			if ((texture[i][0] -> sizeX)%4) texture[i][0] -> sizeX = texture[i][0] -> sizeX + (4-(texture[i][0] -> sizeX));
			if ((texture[i][1] -> sizeX)%4) texture[i][1] -> sizeX = texture[i][1] -> sizeX + (4-(texture[i][0] -> sizeX));
			if ((texture[i][0] -> sizeY)%4) texture[i][0] -> sizeY = texture[i][0] -> sizeY + (4-(texture[i][0] -> sizeY));
			if ((texture[i][1] -> sizeY)%4) texture[i][1] -> sizeY = texture[i][1] -> sizeY + (4-(texture[i][0] -> sizeY));

			nbTexL++;
		 }

		 responses[i]="";
	  }

	  responses[8]="YOU ARE NOT THIRSTY YET!";
	  responses[9]="YOU ARE NOT THIRSTY YET!";
	  responses[11]="QKSHJGDKEZAFRLQWSLHW;;:";
	  responses[12]="\"WATCH MAAAAAAH...\"";

	  texpspFpuFloor = oslLoadImageFilePNG("./gfx/texs/fl0.png",OSL_IN_VRAM, OSL_PF_8888);

	  sprs[0] = oslLoadImageFilePNG("./gfx/sprs/s0.png",OSL_IN_RAM, OSL_PF_5551);

	  for (i=1; i<256; i++)
	  {
			 oslStartDrawing();
			 oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));
			 if (!isCredits)
			 {
				 spr_draw(sfresh, 120, 128);
				 sprintf(path_buffer,"Sprites loaded: %d %%",(int)((nbSpr>0)?(float)(nbSprL*100/nbSpr):100));
				 center(200, path_buffer, RGB(255, 255, 255));
			 }
			 oslEndDrawing();
			 oslSwapBuffers();


		  if (recensedSprites[i]>0)
		  {
			  sprintf(path_buffer,"./gfx/sprs/s%d.png",i);
			  sprs[i] = oslLoadImageFilePNG(path_buffer,OSL_IN_RAM, ((i==134) || (i==135))?OSL_PF_8888:OSL_PF_5551);

			  nbSprL++;
		  }

		  if (i==134)
		  {
			  if (recensedSprites[i])
			  {
				  oslDeleteSound(got_sg);
				  got_sg = oslLoadSoundFileWAV("./sfx/got_sg.wav", OSL_FMT_NONE);
			  }
		  }

		  if (i==135)
		  {
			  if (recensedSprites[i])
			  {
				  oslDeleteSound(got_mg);
				  got_mg = oslLoadSoundFileWAV("./sfx/got_mg.wav", OSL_FMT_NONE);
			  }
		  }

		  if (i==207)
		  {
			  if (recensedSprites[i])
			  {
				  oslDeleteSound(b1_die);
				  b1_die = oslLoadSoundFileWAV("./sfx/boss1_dying.wav", OSL_FMT_NONE);
				  oslDeleteSound(b1_hurt);
				  b1_hurt = oslLoadSoundFileWAV("./sfx/boss1_hurt.wav", OSL_FMT_NONE);
			  }
		  }

		  if (i==172)
		  {
			  if (recensedSprites[i])
			  {
				  oslDeleteSound(boiling);
				  boiling = oslLoadSoundFileWAV("./sfx/boiling.wav", OSL_FMT_NONE);
			  }
		  }

		  if (i==203)
		  {
			  if (recensedSprites[i])
			  {
				  oslDeleteSound(huhaha);
				  huhaha = oslLoadSoundFileWAV("./sfx/huhaha.wav", OSL_FMT_NONE);
			  }
		  }

		  if (i==208)
		  {
			  if (recensedSprites[i])
			  {
				  oslDeleteSound(seeknd);
				  seeknd = oslLoadSoundFileWAV("./sfx/seeknd.wav", OSL_FMT_NONE);
			  }
		  }
	  }



	  hand = oslLoadImageFilePNG("./gfx/hand.png",OSL_IN_RAM, OSL_PF_5551);

	  sceRtcGetCurrentTick( &fpsTickLast );
	  tickResolution = sceRtcGetTickResolution();

      pspFpuFloortexWidth = texpspFpuFloor -> sizeX;
      pspFpuFloortexHeight = texpspFpuFloor -> sizeY;

      if (quality < 1) quality=1;
      if (quality > 4) quality=4;


      rotSpeed=0.0175;
      for (i=0; i<angle; i++)
      {
		  oldDirX = dirX;
		  dirX = dirX * vfpu_cosf(-rotSpeed) - dirY * vfpu_sinf(-rotSpeed);
		  dirY = oldDirX * vfpu_sinf(-rotSpeed) + dirY * vfpu_cosf(-rotSpeed);
		  oldPlaneX = planeX;
		  planeX = planeX * vfpu_cosf(-rotSpeed ) - planeY * vfpu_sinf(-rotSpeed);
		  planeY = oldPlaneX * vfpu_sinf(-rotSpeed) + planeY * vfpu_cosf(-rotSpeed);
      }

      oslStopSound(waiting);
      oslDeleteSound(waiting);

      oslSetSoundLoop(wolfen, 1);
	  oslPlaySound(wolfen, 0);


	  skipframe=0;
	  oslSetFrameskip(1);
	  oslSetMaxFrameskip(1);
	  oslSetFramerate(50);


	  while(!quit)
	  {
		if (!skipframe)
		{
			oslSetTransparentColor(RGB(255,0,255));
			oslSetBkColor(RGB(255,0,255));
			oslSetTextColor(RGBA(255, 255, 0, 64));

			thirst++;

			if (goggles)
			{
				fogType=2;
				if (!menumode) goggles--;

				if (goggles < 200)
				{
					if ((goggles%50) > 24)
					{
						fogType=options[6];
					}
					else
					{
						fogType=2;
					}
				}

				if (!goggles) oslPlaySound(worn_out, 3);
			}
			else
			{
				fogType=options[6];
			}

			if ((health <= 0) && (!deathFrame))
			{
				health=0;
				oslStopSound(wolfen);
				oslPlaySound(urdead, 7);
			}

			if (deathcause >= 2)
			{
				deathFrame++;
				if (deathFrame==16) quit=1;
			}

			if ((mindfuck) && (!menumode))
			{
				w = 360 + 120 * vfpu_sinf(0.5*mindfuck);
				h = 232 + 40 * vfpu_sinf(0.5*mindfuck+45);
				mindfuck--;
				shrooms=RGB(random(255), random(255), random(255));

				if (!mindfuck)
				{
					w=options[1];
					h=options[2];
				}
			}

			respir = (health > 0)?4 * vfpu_sinf(bobbing*frame):0;
			if ((mindfuck) && (!menumode)) respir=respir+(random(50)-25);

			torchlight = (fps%2)?random(32):0;
			if (frameshot) torchlight=torchlight-frameshot;

		  	oslStartDrawing();

		  	oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));

		  	if (fogType != 2)
		  	{
				oslDrawGradientRect((480-w)/2, 136, ((480-w)/2)+w, (272-h)/2+h, RGB(0, 0, 0), RGB(0, 0, 0), RGB(floor_color[0], floor_color[1], floor_color[2]), RGB(floor_color[0], floor_color[1], floor_color[2])); //RGB(108, 92, 80), RGB(108, 92, 80));

				if (fogType != 1)
				{
					oslDrawGradientRect((480-w)/2, (272-h)/2, ((480-w)/2)+w, 136, RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]), RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]), RGB(0, 0, 0), RGB(0, 0, 0));
				}
				else
				{
					sky -> stretchX = w;
					sky -> stretchY = h/2;

					spr_draw(sky,(480-w)/2, (272-h)/2);
				}
		  	}
		  	else
		  	{
		  		oslDrawFillRect((480-w)/2, 136, ((480-w)/2)+w, (272-h)/2+h, RGB(floor_color[0], floor_color[1], floor_color[2]));
		  		oslDrawFillRect((480-w)/2, (272-h)/2, ((480-w)/2)+w, 136,  RGB(ceiling_color[0], ceiling_color[1], ceiling_color[2]));
		  	}


			for(x = 0; x < w; x=x+quality)
			{
				  sceRtcGetCurrentTick( &fpsPreviousTick );
				  //calculate ray position and direction
				  cameraX = (2*x/((float)w))-1; //x-coordinate in camera space
				  rayPosX = (float)posX;
				  rayPosY = (float)posY;
				  rayDirX = dirX + planeX*cameraX;
				  rayDirY = dirY + planeY*cameraX;

				  mapX = (int)rayPosX;
				  mapY = (int)rayPosY;

				  if (rayDirX == 0) rayDirX = (random(2)?-1:1)*0.0001;
				  if (rayDirY == 0) rayDirY = (random(2)?-1:1)*0.0001;

				  deltaDistX = vfpu_powf(0.5, 1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
				  deltaDistY = vfpu_powf(0.5, 1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));

				  hit=0;

				  //calculate step and initial sideDist
				  if (rayDirX < 0)
				  {
					stepX = -1;
					sideDistX = (rayPosX - mapX) * deltaDistX;
				  }
				  else
				  {
					stepX = 1;
					sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX;
				  }
				  if (rayDirY < 0)
				  {
					stepY = -1;
					sideDistY = (rayPosY - mapY) * deltaDistY;
				  }
				  else
				  {
					stepY = 1;
					sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY;
				  }
				  //perform DDA
				  while (!hit)
				  {
					//jump to next map square, OR in x-direction, OR in y-direction
					if (sideDistX < sideDistY)
					{
					  sideDistX += deltaDistX;
					  mapX += stepX;
					  side = 0;
					}
					else
					{
					  sideDistY += deltaDistY;
					  mapY += stepY;
					  side = 1;
					}
					//Check if ray has hit a wall
					if ((worldMap[mapX][mapY] > 1))
					{
						hit = 1;
						worldDiscovered[mapX][mapY]=1;
					}
				  }

				  /*if ((worldMap[mapX][mapY] == 18))
				  {
					  if (!side) rayPosX += (rayDirX > 0)?-0.5:0.5;
					  else	     rayPosY += (rayDirY > 0)?-0.5:0.5;
				  }*/

				  //Calculate distance of perpendicular ray (oblique distance will give fisheye effect!)
				  if (side == 0) perpWallDist = pspFpuAbs(((float)((mapX - rayPosX + (1 - stepX) / 2) / rayDirX)));
				  else           perpWallDist = pspFpuAbs(((float)((mapY - rayPosY + (1 - stepY) / 2) / rayDirY)));

				  if (perpWallDist == 0.0) perpWallDist=0.001;

				  //Calculate height of line to draw on screen
				  lineHeight = abs(h / perpWallDist);

				  //calculate lowest and highest pixel to fill in current stripe
				  drawStart = -lineHeight / 2 + h / 2;
				  drawEnd = lineHeight / 2 + h / 2;

				  //texturing calculations
				  texNum = worldMap[mapX][mapY] - 1; //1 subtracted from it so that texture 0 can be used!
				  textureWidth = texture[texNum][side] -> sizeX;
				  textureHeight = texture[texNum][side] -> sizeY;


				  //calculate value of wallX
				  if (side == 1) wallX = rayPosX + ((mapY - rayPosY + (1 - stepY) / 2) / rayDirY) * rayDirX;
				  else           wallX = rayPosY + ((mapX - rayPosX + (1 - stepX) / 2) / rayDirX) * rayDirY;
				  wallX -= (float)(pspFpuFloor((wallX)));

				  //x coordinate on the texture
				  texX = (int)(wallX * textureWidth);
				  if(side == 0 && rayDirX > 0) texX = textureWidth - texX - 1;
				  if(side == 1 && rayDirY < 0) texX = textureWidth - texX - 1;

				  if (texNum > -1)
				  {
					  k=1;
					  foundAnimated=0;

					  while ((!foundAnimated) && (k < 3))
					  {
						  if (animatedTexs[k][0] == texNum)
						  {
							  textureHeight = animatedTexs[k][1];
							  textureSpeed = animatedTexs[k][2];
							  texNbFrames = animatedTexs[k][3];
							  texAnimatedSides = animatedTexs[k][4];

							  if (!textureSpeed) textureSpeed=1;
							  foundAnimated=1;
						  }
						  k++;
					  }

					  if (texAnimatedSides != side) foundAnimated=0;
					  if (texAnimatedSides == 2) foundAnimated=1;

					  if (!foundAnimated)
					  {
						  textureHeight = texture[texNum][side] -> sizeY;
						  textureSpeed=1;
						  texNbFrames=1;
					  }


					  oslSetImageTileSize(texture[texNum][side], abs(texX), textureHeight*((frame%(texNbFrames*textureSpeed))/textureSpeed), quality, textureHeight);


					  texture[texNum][side] -> stretchY = (abs(drawStart-drawEnd));


					  if (((480-w)/2+x)==240)
					  {
						  facingTexture=texNum;
						  distToFacingTex=perpWallDist;
						  facingSide=side;
					  }

			          //dark = -255/h * (abs(drawStart-drawEnd)>h?h:abs(drawStart-drawEnd)) + 255;

						  dark = 255 - (abs(drawStart-drawEnd)) + (h-272) + torchlight;
						  if (dark < 0) dark=0;
						  if (dark > 255) dark=255;
						  if ((texNum == 11) || (texNum == 53)) dark=dark/2;

					  oslSetAlpha(OSL_FX_DEFAULT, 0);

						  if (texNum != 999)
						  {
							  spr_draw(texture[texNum][side], (480-w)/2+x, (272-h)/2+drawStart+respir);
						  }
						  else
						  {
							  spr_draw(sidedoor, (480-w)/2+x, (272-h)/2+drawStart+respir);
						  }


					  switch(fogType)
					  {
					  	  case 0:
					  		  oslSetAlpha(OSL_FX_TINT, RGBA(0, 0, 0, dark));
					  	  break;

					  	  case 1:
					  		  oslSetAlpha(OSL_FX_TINT, RGBA(255, 255, 0, 255-dark));
					  	  break;
					  }

					  if (mindfuck)
					  {
						  oslSetAlpha(OSL_FX_TINT, shrooms/2);

						  if (texNum != 999)
						  {
							  spr_draw(texture[texNum][side], (480-w)/2+x, (272-h)/2+drawStart+respir);
						  }
						  else
						  {
							  spr_draw(sidedoor, (480-w)/2+x, (272-h)/2+drawStart+respir);
						  }

						  oslSetAlpha(OSL_FX_DEFAULT, 0);
					  }
					  else
					  {
						  if (fogType < 2)
						  {
							  if (texNum != 999)
							  {
								  spr_draw(texture[texNum][side], (480-w)/2+x, (272-h)/2+drawStart+respir);
							  }
							  else
							  {
								  spr_draw(sidedoor, (480-w)/2+x, (272-h)/2+drawStart+respir);
							  }
							  oslSetAlpha(OSL_FX_DEFAULT, 0);
						  }
					  }
					  //oslResetImageProperties(texture[texNum][side]);
				  }

			      //SET THE ZBUFFER FOR THE SPRITE CASTING
			      for(i=x; i<(x+quality); i++) ZBuffer[i] = perpWallDist; //perpendicular distance is used

				  //FLOOR CASTING
				        //x, y position of the FLOOR texel at the bottom of the wall

				        //4 different wall directions possible
				  if (sol == 34512)
				  {
				        if(side == 0 && rayDirX > 0)
				        {
				          pspFpuFloorXWall = mapX;
				          pspFpuFloorYWall = mapY + wallX;
				        }
				        else if(side == 0 && rayDirX < 0)
				        {
				          pspFpuFloorXWall = mapX + 1.0;
				          pspFpuFloorYWall = mapY + wallX;
				        }
				        else if(side == 1 && rayDirY > 0)
				        {
				          pspFpuFloorXWall = mapX + wallX;
				          pspFpuFloorYWall = mapY;
				        }
				        else
				        {
				          pspFpuFloorXWall = mapX + wallX;
				          pspFpuFloorYWall = mapY + 1.0;
				        }

				        distWall = perpWallDist;
				        distPlayer = 0.0;

				        if (drawEnd < 0) drawEnd = h; //becomes < 0 when the integer overflows

				        //draw the pspFpuFloor from drawEnd to the bottom of the screen

				        for(y = drawEnd+1; y < h; y+=quality)
				        {
				          currentDist = h / (2*y-h); //you could make a small lookup table for this instead

				          weight = (currentDist - distPlayer) / (distWall - distPlayer);

				          currentpspFpuFloorX = weight * pspFpuFloorXWall + (1.0 - weight) * posX;
				          currentpspFpuFloorY = weight * pspFpuFloorYWall + (1.0 - weight) * posY;

				          pspFpuFloorTexX = (int)(currentpspFpuFloorX * pspFpuFloortexWidth) % pspFpuFloortexWidth;
				          pspFpuFloorTexY = (int)(currentpspFpuFloorY * pspFpuFloortexHeight) % pspFpuFloortexHeight;


				          oslSetImageTileSize(texpspFpuFloor, abs(pspFpuFloorTexX), abs(pspFpuFloorTexY), quality*4, quality*4);


				          dark = 128 - (abs(y)) + (h-136) + torchlight;
						  if (dark < 0) dark=0;
						  if (dark > 255) dark=255;

						  oslSetAlpha(OSL_FX_DEFAULT, 0);
						  if (sol) spr_draw(texpspFpuFloor, (480-w)/2+x, (272-h)/2+y+respir);
						  //if (ceiling) spr_draw(texpspFpuFloor, (480-w)/2+x, (272-h)/2+h-y);

						  oslSetAlpha(OSL_FX_TINT, RGBA(0, 0, 0, dark));
						  if (sol) spr_draw(texpspFpuFloor, (480-w)/2+x, (272-h)/2+y+respir);
						  //if (ceiling) spr_draw(texpspFpuFloor, (480-w)/2+x, (272-h)/2+h-y);

						  oslSetAlpha(OSL_FX_DEFAULT, 0);

				        }
				  }

			}

			//SPRITE CASTING
			//sort sprites from far to close
			for(i = 0; i < nbSprites; i++)
			{
			  spriteOrder[i] = i;
			  if (sprite[i].x != -1)
			  {
				  spriteDistance[i] = ((posX - sprite[i].x) * (posX - sprite[i].x) + (posY - sprite[i].y) * (posY - sprite[i].y)); //sqrt not taken, unneeded
			  }
			  else
			  {
				  spriteDistance[i] = 16384;
			  }

			  visibleSprite[spriteOrder[i]]=0;
			}

			//combSort(spriteOrder, spriteDistance, nbSprites); <- Comb Sort, in lodev's tutorial by default, slow!
			selSort(spriteOrder, spriteDistance, nbSprites); //Selection Sort, so-so performance
			//quickSort(spriteOrder, spriteDistance, 0, nbSprites); //QuickSort, can handle numerous sprites, struggles with close sprites
			//heapSort(spriteOrder, spriteDistance, nbSprites); //can handle numerous sprites
			//introSort(spriteOrder, spriteDistance, nbSprites); //implement it properly plox.

			//after sorting the sprites, do the projection and draw them
			for(i = 0; i < nbSprites; i++)
			{
				  //translate sprite position to relative to camera
				  spriteX = sprite[spriteOrder[i]].x - posX;
				  spriteY = sprite[spriteOrder[i]].y - posY;

				  spritePosX=pspFpuFloor(sprite[spriteOrder[i]].x);
				  spritePosY=pspFpuFloor(sprite[spriteOrder[i]].y);



				  //transform sprite with the inverse camera matrix
				  // [ planeX   dirX ] -1                                       [ dirY      -dirX ]
				  // [               ]       =  1/(planeX*dirY-dirX*planeY) *   [                 ]
				  // [ planeY   dirY ]                                          [ -planeY  planeX ]

				  j = (planeX * dirY - dirX * planeY);

				  if (j == 0) j=(random(2)?-1:1)*0.0001;

				  invDet = 1.0 / j; //required for correct matrix multiplication

				  transformX = invDet * (dirY * spriteX - dirX * spriteY);
				  transformY = invDet * (-planeY * spriteX + planeX * spriteY); //this is actually the depth inside the screen, that what Z is in 3D

				  if (transformY == 0) transformY = 0.0001;

				  spriteScreenX = (int)((w / 2) * (1 + transformX / transformY));

				  //parameters for scaling and moving the sprites
				  vMoveScreen = (int)(vMove / transformY);

				  //calculate height of the sprite on screen
				  spriteHeight = abs((int)(h / (transformY))) / vDiv; //using "transformY" instead of the real distance prevents fisheye
				  //calculate lowest and highest pixel to fill in current stripe
				  drawStartY = -spriteHeight / 2 + h / 2 + vMoveScreen;
				  //if(drawStartY < 0) drawStartY = 0;
				  drawEndY = spriteHeight / 2 + h / 2 + vMoveScreen;
				  //if(drawEndY >= h) drawEndY = h - 1;

				  //calculate width of the sprite
				  spriteWidth = abs( (int) (h / (transformY))) / uDiv;
				  drawStartX = -spriteWidth / 2 + spriteScreenX;
				  if(drawStartX < -quality) drawStartX = -quality;
				  drawEndX = spriteWidth / 2 + spriteScreenX;
				  if(drawEndX >= w) drawEndX = w - quality;

				  //loop through every vertical stripe of the sprite on screen
				  for(stripe = drawStartX; stripe < drawEndX; stripe+=quality)
				  {
					texX = (int)((256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * (sprs[sprite[spriteOrder[i]].texture] -> sizeX) / spriteWidth) / 256);

					//the conditions in the if are:
					//1) it's in front of camera plane so you don't see things behind you
					//2) it's on the screen (left)
					//3) it's on the screen (right)
					//4) ZBuffer, with perpendicular distance

					if(transformY > 0 && stripe > 0 && stripe < w && transformY < ZBuffer[stripe] && (sprite[spriteOrder[i]].texture > 0) && (spriteDistance[i] != 16384))
					{
						visibleSprite[spriteOrder[i]]=1;

						if (sprite[spriteOrder[i]].texture < 128)
						{
							spriteDiscovered[spritePosX][spritePosY]=1;
						}
						else if (sprite[spriteOrder[i]].texture >= 192)
						{
							spriteDiscovered[spritePosX][spritePosY]=2;
						}

						if ((sprite[spriteOrder[i]].texture >= 160) && (sprite[spriteOrder[i]].texture < 192))
						{
							spriteDiscovered[spritePosX][spritePosY]=4;
						}

						if ((sprite[spriteOrder[i]].texture >= 128) && (sprite[spriteOrder[i]].texture < 160))
						{
							spriteDiscovered[spritePosX][spritePosY]=3;
						}


						if (sprite[spriteOrder[i]].texture == 192)
						{
							if (sprite[spriteOrder[i]].wokenUp == 0)
							{
								oslPlaySound(enemy, 7);
								sprite[spriteOrder[i]].discovered = 1;
							}
							sprite[spriteOrder[i]].wokenUp = 501;
						}

						if (sprite[spriteOrder[i]].texture == 197)
						{
							if (sprite[spriteOrder[i]].discovered == 0)
							{
								oslPlaySound(grunt, 7);
								sprite[spriteOrder[i]].discovered = 1;
							}

							if (sprite[spriteOrder[i]].wokenUp == 0)
							{
								sprite[spriteOrder[i]].texture = 198;
								sprite[spriteOrder[i]].wokenUp = 66+random(8);
							}
						}

						if (sprite[spriteOrder[i]].texture == 202)
						{
							if (sprite[spriteOrder[i]].discovered == 0)
							{
								oslPlaySound(huhaha, 7);
								sprite[spriteOrder[i]].discovered = 1;
							}

							if (sprite[spriteOrder[i]].wokenUp == 0)
							{
								sprite[spriteOrder[i]].texture = 203;
								sprite[spriteOrder[i]].wokenUp = 66+random(8);
							}
						}

						if (sprite[spriteOrder[i]].texture == 207)
						{
							if (sprite[spriteOrder[i]].discovered == 0)
							{
								oslPlaySound(seeknd, 7);
								sprite[spriteOrder[i]].discovered = 1;
							}

							if (sprite[spriteOrder[i]].wokenUp == 0)
							{
								sprite[spriteOrder[i]].texture = 208;
								sprite[spriteOrder[i]].wokenUp = 66+random(8);
							}
						}

						if (sprite[spriteOrder[i]].wokenUp >= 0)
						{
							  k=0;
							  foundAnimated=0;

							  while ((!foundAnimated) && (k < 12))
							  {
								  if (animatedSprs[k][0] == sprite[spriteOrder[i]].texture)
								  {
									  spriteAnimHeight = animatedSprs[k][1];
									  spriteSpeed = animatedSprs[k][2];
									  sprNbFrames = animatedSprs[k][3];

									  if (!spriteSpeed) textureSpeed=1;
									  foundAnimated=1;
								  }
								  k++;
							  }
						}
						else
						{
							foundAnimated=0;
						}

						if (!(foundAnimated))
						{
							oslSetImageTileSize(sprs[sprite[spriteOrder[i]].texture], abs(texX), 0, quality, sprs[sprite[spriteOrder[i]].texture] -> sizeY);
						}
						else
						{
							if ((sprite[spriteOrder[i]].texture != 193) &&
								(sprite[spriteOrder[i]].texture != 195) &&
								(sprite[spriteOrder[i]].texture != 198) &&
								(sprite[spriteOrder[i]].texture != 200) &&
								(sprite[spriteOrder[i]].texture != 203) &&
								(sprite[spriteOrder[i]].texture != 205) &&
								(sprite[spriteOrder[i]].texture != 208) &&
								(sprite[spriteOrder[i]].texture != 210))
							oslSetImageTileSize(sprs[sprite[spriteOrder[i]].texture], abs(texX), spriteAnimHeight*((frame%(sprNbFrames*spriteSpeed))/spriteSpeed), quality, spriteAnimHeight);

							switch(sprite[spriteOrder[i]].texture)
							{
								case 193:
								case 195:
								case 198:
								case 200:
								case 203:
								case 205:
								case 208:
								case 210:
									oslSetImageTileSize(sprs[sprite[spriteOrder[i]].texture], abs(texX), spriteAnimHeight*(((24-sprite[spriteOrder[i]].wokenUp)%(sprNbFrames*spriteSpeed))/spriteSpeed), quality, spriteAnimHeight);
								break;
							}
						}

							sprs[sprite[spriteOrder[i]].texture] -> stretchX = quality;
							sprs[sprite[spriteOrder[i]].texture] -> stretchY = (abs(drawStartY-drawEndY));

						  //dark = -255/h * (abs(drawStart-drawEnd)>h?h:abs(drawStart-drawEnd)) + 255;

						  dark = 255 - (abs(drawStartX-drawEndX)) + (h-272) + torchlight;
						  if (dark < 0) dark=0;
						  if (dark > 255) dark=255;

						  oslSetAlpha(OSL_FX_DEFAULT, 0);
						  spr_draw(sprs[sprite[spriteOrder[i]].texture], (480-w)/2+stripe, (272-h)/2+drawStartY+respir);

						  switch(fogType)
						  {
						  	  case 0:
						  		  oslSetAlpha(OSL_FX_TINT, RGBA(0, 0, 0, dark));
						  	  break;

						  	  case 1:
						  		  oslSetAlpha(OSL_FX_TINT, RGBA(255, 255, 0, dark));
						  	  break;
						  }


						  if (mindfuck)
						  {
							  oslSetAlpha(OSL_FX_TINT, shrooms);
							  spr_draw(sprs[sprite[spriteOrder[i]].texture], (480-w)/2+stripe, (272-h)/2+drawStartY+respir);
						  }
						  else
						  {
							  if ((fogType < 2) && (isNotLight(sprite[spriteOrder[i]].texture)))
							  {
								  if (!(isFiring(sprite[spriteOrder[i]].wokenUp, sprite[spriteOrder[i]].texture)))
								  {
									  if ((worldSprites[spritePosX][spritePosY] != 166) &&
										  (worldSprites[spritePosX][spritePosY] != 167) &&
										  (worldSprites[spritePosX][spritePosY] != 168) &&
										  (worldSprites[spritePosX][spritePosY] != 171))
									  {
										  spr_draw(sprs[sprite[spriteOrder[i]].texture], (480-w)/2+stripe, (272-h)/2+drawStartY+respir);
									  }
								  }

							  }
						  }


						  oslSetAlpha(OSL_FX_DEFAULT, 0);
					}
					else
					{
						visibleSprite[spriteOrder[i]]=0;
					}

					if ((((480-w)/2+stripe) >= 232) && (((480-w)/2+stripe) <= 248))
					{
						//making some sprites "invisible" so enemies cannot protect behind them
						if ((sprite[spriteOrder[i]].texture != 206) &&
							(sprite[spriteOrder[i]].texture != 201) &&
							(sprite[spriteOrder[i]].texture != 196) &&
							((sprite[spriteOrder[i]].texture < 128) ||
							 (sprite[spriteOrder[i]].texture >= 192)))
						{
							distToSprite=spriteDistance[i];
							facingSprite=sprite[spriteOrder[i]].texture;
							facingSpriteNumber=spriteOrder[i];

							switch(facingSprite)
							{
								case 192:
								case 193:
								case 194:
									lowBoundsprChunk=23;
									hiBoundsprChunk=40;
								break;

								case 197:
								case 198:
								case 199:
									lowBoundsprChunk=21;
									hiBoundsprChunk=43;
								break;

								case 202:
								case 203:
								case 204:
									lowBoundsprChunk=14;
									hiBoundsprChunk=45;
								break;

								case 207:
								case 208:
								case 209:
									lowBoundsprChunk=3;
									hiBoundsprChunk=60;
								break;
							}

							if ((texX >= lowBoundsprChunk) && (texX <= hiBoundsprChunk))
							{
								sprChunk = texX;
							}
							else
							{
								sprChunk = 0;
							}
						}
					}

				  }

			}

			oslDrawFillRect(0, 0, 480, (272-h)/2, RGB(0, 0, 0));
			oslDrawFillRect(0, (272-h)/2+h, 480, 272, RGB(0, 0, 0));
			oslDrawFillRect(w/2+240, 0, 480, 272, RGB(0, 0, 0));



					for (i=0; i<MAXSPRITES; i++)
					{
						pickedup=0;
						if ((sprite[i].texture >= 128) && ((sprite[i].texture < 192)))
						{
							j=((posX - sprite[i].x) * (posX - sprite[i].x) + (posY - sprite[i].y) * (posY - sprite[i].y));

							if (j < 0.4)
							{
								if ((sprite[i].texture >= 128) && (sprite[i].texture < 160))
								{
									spritePosX = sprite[i].x;
									spritePosY = sprite[i].y;
									spriteDiscovered[spritePosX][spritePosY]=0;
								}

									switch(sprite[i].texture)
									{
										case 128:
											if (health < 100)
											{
												health += 10;
												oslPlaySound(aah, 3);
												pickedup=1;
											}
										break;

										case 129:
											if (health < 100)
											{
												health += 25;
												oslPlaySound(aah, 3);
												pickedup=1;
											}
										break;

										case 130:
											if (ammo < 98)
											{
												ammo += 8;
												oslPlaySound(load, 3);
												pickedup=1;
											}
										break;

										case 131:
											if (ammo < 83)
											{
												ammo += 25;
												oslPlaySound(load, 3);
												pickedup=1;
											}
										break;

										case 132:
											coins += 2;
											oslPlaySound(coins_sound, 3);
											pickedup=1;
										break;

										case 133:
											coins++;
											oslPlaySound(coins_sound, 3);
											pickedup=1;
										break;

										case 134:
											weaponPossessed[2]=1;

											if (!weaponPossessed[3])
											{
												weapon=2;
												weaponY=-96;
											}

											oslPlaySound(got_sg, 3);
											pickedup=1;

											if (ammo < 98) ammo += 8;
										break;

										case 135:
											if (!weaponPossessed[3]) weaponY=-96;

											weaponPossessed[3]=1;
											weapon=3;
											oslPlaySound(got_mg, 3);
											pickedup=1;

											if (ammo < 95) ammo += 12;
										break;

										case 136:
											oslPlaySound(coins_sound, 3);
											doorkeys[0]=1;
											pickedup=1;
										break;

										case 137:
											oslPlaySound(coins_sound, 3);
											doorkeys[1]=1;
											pickedup=1;
										break;

										case 138:
											oslPlaySound(coins_sound, 3);
											doorkeys[2]=1;
											pickedup=1;
										break;

										case 139:
											if (health < 100)
											{
												health += 5;
												oslPlaySound(aah, 3);
												pickedup=1;
											}
										break;

										case 140:
											mindfuck=1500;
											oslPlaySound(vomit, 3);
											pickedup=1;
										break;

										case 141:
											if (armor < 100)
											{
												armor=100;
												oslPlaySound(got_sg, 3);
												pickedup=1;
											}
										break;

										case 142:
											health+=100;
											if (health > 200) health=200;
											oslPlaySound(supercharge, 3);
											pickedup=1;
										break;

										case 143:
											goggles=1500;
											pickedup=1;
										break;

										case 172:
											if ((health) && (oslGetSoundChannel(boiling) != 4)) oslPlaySound(boiling, 2);

											if (!(frame%3))
											{
												if (health > 0)
												{
													health--;
												}
												else
												{
													oslStopSound(boiling);
													oslStopSound(wolfen);
													if ((oslGetSoundChannel(urdead) != 7) && (!deathcause))
													{
														oslPlaySound(urdead, 7);
														deathcause=4;
													}
												}
											}
										break;
									}

									//worldSprites[(int)(pspFpuFloor(posX))][(int)(pspFpuFloor(posY))]=0;

									if (pickedup)
									{
										messagetime=360;
										messagepick=sprite[i].texture-128;

										sprite[i].x = -1;
										sprite[i].y = -1;
										sprite[i].texture = 0;



										pickedup=0;
										facingSprite=0;
										break;

										nbSprites=0;

										for(cspr=0; cspr<MAXSPRITES; cspr++)
										{
											if (sprite[cspr].x == -1)
											{
												nbSprites++;
											}
										}
									}

							}
						}
					}



			if ((doorTrans > 1) && (DOORTYPELIKE == 1))
			{
				oslDrawFillRect(0, 0, 480, 272, RGBA(0, 0, 0, ((doorTrans > 64)?(128-doorTrans)*4:((doorTrans == 64)?255:4*doorTrans))));
				doorTrans -= 2;

				if (doorTrans == 64)
				{
					if (!facingSide) posX += ((rayDirX > 0)?1:-1)*1.70;
					else	   		 posY += ((rayDirY > 0)?1:-1)*1.70;
				}
			}

			if (DOORTYPELIKE == 2)
			{
				for (k=0; k<mapWidth; k++)
				{
					for (l=0; l<mapHeight; l++)
					{
						if ((worldDoorTimers[k][l] > 1) && (k != (pspFpuFloor(posX))) && (l != (pspFpuFloor(posY)))) worldDoorTimers[k][l]--;

						if (worldDoorTimers[k][l] == 2) oslPlaySound(door_close, 1);

						if (worldDoorTimers[k][l] == 1)
						{
							worldMap[k][l]=worldDoors[k][l];
							worldDiscovered[k][l]=1;
						}
					}
				}
			}

			if (messagetime > 1)
			{
				messagetime-=4;

				if (messagepick > -1)
				{
					oslSetAlpha(OSL_FX_ALPHA, messagetime>255?255:messagetime);
					amigatext(msgpicks[messagepick], 999, 64, amiga, 8, 8);
					oslSetAlpha(OSL_FX_DEFAULT, 0);
					messageno_s = -1;
					messageno=-1;
				}

				if (messageno > -1)
				{
					oslSetAlpha(OSL_FX_ALPHA, messagetime>255?255:messagetime);
					amigatext(responses[messageno], 999, 64, amiga, 8, 8);
					oslSetAlpha(OSL_FX_DEFAULT, 0);
					messageno_s = -1;
					messagepick=-1;
				}

				if (messageno_s > -1)
				{
					oslSetAlpha(OSL_FX_ALPHA, messagetime>255?255:messagetime);
					amigatext(responses2[messageno_s], 999, 64, amiga, 8, 8);
					oslSetAlpha(OSL_FX_DEFAULT, 0);
					messageno=-1;
					messagepick=-1;
				}

			}
			else
			{
				messagetime=0;
				messageno=-1;
				messageno_s=-1;
				messagepick=-1;
			}

			if ((facingTexture == 17) && (distToFacingTex <= 0.20))
			{
				amigatext("PRESS CIRCLE TO USE THE DOOR", 999, 112, amiga, 8, 8);
			}

			if ((isCredits) && (frame%600 > 10) && (frame%600 < 510))
			{
				center(32, credits[frame/600], RGB(255, 255, 255));
			}

			if (!isCredits)
			{
				if ((weaponY==16) && (weapon))
				{
					spr_draw(weapon_fire, 0.641*w+(480-w)/2, (0.713*h)+((272-h)/2)-weaponY+(respir/2));
				}

				weapons[weapon] -> stretchX = w/2;
				weapons[weapon] -> stretchY = 0.470*h;

				spr_draw(weapons[weapon], 240, 136+0.09*h-0.588*h/2+h/3-weaponY+(respir/2));
				if (weaponY > 0) weaponY -= 2; else if (weaponY < 0) weaponY += 8;

				oslDrawFillRect(0, (272-h)/2+h, 480, 272, RGB(0, 0, 0));


				drawHealth(health, ammo, coins, armor, digits, bullet, coin, fps, doorkeys, minikeys, armor_icon);
			}

			if (frameshot > 0) frameshot--;

			if (menumode)
			{
				mainmenu(options[0], options[1], options[2], options[3], options[4], options[5], options[6], options[7], options[8], chm, hand);
				//mainmenu(quality, w, h, keepratio, sol, vsync, fogType, quit, chm, hand);
				if (isCredits) frame--;
			}

			fps++;
			frame++;

			sceRtcGetCurrentTick( &fpsTickNow );

			frameTime = fpsTickNow - fpsTickLast;

				if ((tickResolution > 0) && (fps))
				{
					if( ((frameTime)/((float)tickResolution)) >= 1.0f )
					{
						fpsTickLast = fpsTickNow;
						fps_to_display=fps;
						fps = 0;

						if ((!menumode) && (health > 100)) health--;
					}
				}

			/*if (fps_to_display) frame_debug(fps_to_display);

			  sprintf(path_buffer,"%d", (int)oslGetRamStatus().maxAvailable);
			  oslDrawString(0, 8, path_buffer);*/

			if ((sol) && (vsync))
			{
				if (fps_to_display < 60)
				{
					if (qualityFrame < 0) qualityFrame=0;
					qualityFrame++;
				}

				if (fps_to_display >= 60) qualityFrame--;

				if (qualityFrame > fps_to_display)
				{
					if (quality < 4)
					{
						quality++;
						qualityFrame=0;
					}
				}
				else if (qualityFrame < 0)
				{
					if (quality > 1)
					{
						quality--;
						qualityFrame=fps_to_display-1;
					}
				}
			}

			if (health <= 0)
			{
				deathFrame+=2;
				if (deathFrame < 272)
				{
					dead(deathFrame+2, RGBA(255, 0, 0, (deathFrame<255)?deathFrame:255));

				}
				else
				{
					dead(272, RGB(255, 0, 0));
					quit=1;
				}
			}

			if ((mapMode) && (!menumode) && (!isCredits))
			{
				for (k=0; k<mapWidth; k++)
				{
					for (l=0; l<mapHeight; l++)
					{
						if (worldDiscovered[k][l])
						{
							oslDrawFillRect(112+l*4,8+k*4,116+(l)*4,12+k*4, RGBA(192, 192, 192, 32));
						}

						if (spriteDiscovered[k][l])
						{
							switch(spriteDiscovered[k][l])
							{
								case 1:
								oslDrawFillRect(112+l*4,8+k*4,116+(l)*4,12+k*4, RGBA(0, 0, 128, 32));
								break;

								case 2:
								oslDrawFillRect(112+l*4,8+k*4,116+(l)*4,12+k*4, RGBA(255, 0, 0, 32));
								break;

								case 3:
								oslDrawFillRect(112+l*4,8+k*4,116+(l)*4,12+k*4, RGBA(0, 128, 0, 32));
								break;

								case 4:
								oslDrawFillRect(112+l*4,8+k*4,116+(l)*4,12+k*4, RGBA(64, 64, 0, 32));
								break;
							}
						}
					}
				}

				if ((frame%fps_to_display) < (fps_to_display/2))
				{
					oslDrawFillRect(112+((int)posY)*4,8+((int)posX)*4,116+((int)posY)*4,12+((int)posX)*4, RGBA(255, 255, 0, 64));
				}
			}

			oslEndDrawing();

			if (vsync)
			{
				oslEndFrame();
				skipframe=oslSyncFrame();
			}
			else
			{
				oslSwapBuffers();
				skipframe=0;
			}



			//speed modifiers
			moveSpeed = 0.01047; //the constant value is in squares/second
			rotSpeed = 0.008725; //the constant value is in radians/second

			if (mindfuck) rotSpeed = 0.008725*(random(4)+1);

				oslReadKeys();

				if ((osl_keys->pressed.start) && (health > 0))
				{
					if (!menumode) menumode=1; else menumode=0;
				}

				if ((osl_keys->pressed.square) && (health > 0) && (frame > 120))
				{
					if (!mapMode) mapMode=1; else mapMode=0;
				}

				if (menumode)
				{
					if ((osl_keys->pressed.up) && (chm > 0))
					{
						chm--;
					}
					if ((osl_keys->pressed.down) && (chm < 8))
					{
						chm++;
					}

					if ((osl_keys->held.left))
					{
						switch(chm)
						{
							case 0:
							if (options[1] > 200)
							{
								options[1]--;
								if (options[3]) options[2]=(int)((float)(options[1]/1.76));
							}
							break;

							case 1:
							if (!options[3])
							{
								if (options[2] > 48) options[2]--;
							}
							break;
						}
					}

					if ((osl_keys->held.right))
					{
						switch(chm)
						{
							case 0:
							if (options[1] < 480)
							{
								options[1]++;
								if (options[3]) options[2]=(int)((float)(options[1]/1.76));
								if (options[2]>272) options[2]=272;
							}

							break;

							case 1:
							if (!options[3])
							{
								if (options[2] < 272) options[2]++;
							}
							break;
						}
					}

					if ((osl_keys->pressed.right) || (osl_keys->pressed.left) || (osl_keys->pressed.circle) || (osl_keys->pressed.cross))
					{
						switch(chm)
						{
							case 2:
							if (!options[3])
							{
								options[3]=1;
							}
							else options[3]=0;
							break;

							case 3:
							if (osl_keys->pressed.right)
							{
								options[0]++;
								if (options[0]==5) options[0]=1;
							}
							else if (osl_keys->pressed.left)
							{
								options[0]--;
								if (options[0]==0) options[0]=4;
							}
							break;

							case 4:
								if (!options[4]) options[4]=1; else options[4]=0;
							break;

							case 5:
								if (!options[5]) options[5]=1; else options[5]=0;
							break;

							case 6:
								/*if (osl_keys->pressed.right)
								{
									options[6]++;
									options[6]=options[6]%3;
								}
								else if (osl_keys->pressed.left)
								{
									options[6]--;
									if (options[6]) options[6]=2;
								}*/
							break;

							case 7:
								if (osl_keys->held.right)
								{
									if (options[8] < 100) options[8]+=4;
								}
								else if (osl_keys->held.left)
								{
									if (options[8] > 0) options[8]-=4;
								}

								oslPauseSound(wolfen, 1);
								  wolfen -> volumeLeft = 163.84 * options[8];
								  wolfen -> volumeRight = 163.84 * options[8];
								oslPauseSound(wolfen, 0);

							break;

							case 8:
							if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
							{
								deathcause=2;
								oslStopSound(wolfen);
							}
							break;
						}
					}

					quality=options[0];
					w=options[1];
					h=options[2];
					sol=options[4];
					vsync=options[5];
					fogType=options[6];
				}
				else if ((!menumode) && (health > 0))
				{
					if (osl_keys->pressed.circle)
					{
						messagetime=0;
						messageno=-1;
						messageno_s=-1;
						messagepick=-1;

						if ((distToSprite <= 0.4) && (transformY > 0))
						{
							messageno=-1;
							messageno_s=-1;
							messagepick=-1;
							messagetime=360;
							messageno_s=facingSprite;
						}

						if ((distToFacingTex <= 0.625))
						{
							i=pspFpuFloor(worldMap[mapX][mapY]-1);

							switch(i)
							{
								case 8:
								case 9:
									if ((thirst >= 1800) && (((i==8) && (!facingSide))  || ((i==9) && (facingSide))))
									{
										messageno=-1;
										messageno_s=-1;
										messagepick=-1;

										if (coins > 0)
										{
											if (worldVendings[mapX][mapY] > 0)
											{
												if (health < 100)
												{
													worldVendings[mapX][mapY]--;
													coins--;

													responses[8]="HOW REFRESHING!";
													responses[9]="HOW REFRESHING!";
													oslPlaySound(gulp, 6);
													health += 2;
													if (health > 100) health=100;
													thirst -= 400;
												}
												else
												{
													responses[8]="YOU ARE NOT THIRSTY YET!";
													responses[9]="YOU ARE NOT THIRSTY YET!";
												}
											}
											else
											{
												responses[8]="THIS MACHINE IS EMPTY...";
												responses[9]="THIS MACHINE IS EMPTY...";
											}
										}
										else
										{
											responses[8]="YOU DO NOT HAVE ANY CREDITS!";
											responses[9]="YOU DO NOT HAVE ANY CREDITS!";
										}
									}
									else
									{
										responses[8]="YOU ARE NOT THIRSTY YET!";
										responses[9]="YOU ARE NOT THIRSTY YET!";
									}
								break;

								case 10:
									if (!(facingSide) && (distToFacingTex <= 0.625))
									{
										worldMap[mapX][mapY]=12;
										facingTexture=11;
										oslPlaySound(uhcakip, 5);
									}
								break;

								case 11:
									if (!(facingSide) && (distToFacingTex <= 0.625))
									{
										worldMap[mapX][mapY]=11;
										facingTexture=10;
									}
								break;

								case 17:
								case 44:
									if ((DOORTYPELIKE == 1) && (doorTrans < 1) && (distToFacingTex <= 0.2)) doorTrans=128;

									if ((DOORTYPELIKE == 2) && (distToFacingTex <= 0.2))
									{
										worldDoorTimers[mapX][mapY] = 92;
										worldMap[mapX][mapY] = 0;
										worldDiscovered[mapX][mapY] = 0;
										oslPlaySound(door_open, 5);
									}

									messagetime=0;
									messageno=-1;
									messageno_s=-1;
									messagepick=-1;
								break;

								case 18:
									if (distToFacingTex <= 0.2)
									{
										worldMap[mapX][mapY]=20;
										deathcause=3;
										oslPlaySound(endlevel, 7);
									}
								break;

								case 41:
									if (doorkeys[0])
									{
										responses[41]="";


										if ((DOORTYPELIKE == 1) && (doorTrans < 1) && (distToFacingTex <= 0.2)) doorTrans=128;

										if ((DOORTYPELIKE == 2) && (distToFacingTex <= 0.2))
										{
											worldDoorTimers[mapX][mapY] = 92;
											worldMap[mapX][mapY] = 0;
											worldDiscovered[mapX][mapY] = 0;
											oslPlaySound(door_open, 5);
										}


										messagetime=0;
										messageno=-1;
										messageno_s=-1;
										messagepick=-1;
									}
									else
									{
										responses[41]="YOU NEED THE BRONZE KEY!";
									}
								break;

								case 42:
									if (doorkeys[1])
									{
										responses[42]="";


										if ((DOORTYPELIKE == 1) && (doorTrans < 1) && (distToFacingTex <= 0.2)) doorTrans=128;

										if ((DOORTYPELIKE == 2) && (distToFacingTex <= 0.2))
										{
											worldDoorTimers[mapX][mapY] = 92;
											worldMap[mapX][mapY] = 0;
											worldDiscovered[mapX][mapY] = 0;
											oslPlaySound(door_open, 5);
										}


										messagetime=0;
										messageno=-1;
										messageno_s=-1;
										messagepick=-1;
									}
									else
									{
										responses[42]="YOU NEED THE SILVER KEY!";
									}
								break;

								case 43:
									if (doorkeys[2])
									{
										responses[43]="";


										if ((DOORTYPELIKE == 1) && (doorTrans < 1) && (distToFacingTex <= 0.2)) doorTrans=128;

										if ((DOORTYPELIKE == 2) && (distToFacingTex <= 0.2))
										{
											worldDoorTimers[mapX][mapY] = 92;
											worldMap[mapX][mapY] = 0;
											worldDiscovered[mapX][mapY] = 0;
											oslPlaySound(door_open, 5);
										}


										messagetime=0;
										messageno=-1;
										messageno_s=-1;
										messagepick=-1;
									}
									else
									{
										responses[43]="YOU NEED THE GOLD KEY!";
									}
								break;

								default:
									messagetime=0;
									messageno=-1;
									messageno_s=-1;
									messagepick=-1;
								break;
							}

							if ((worldPushable[mapX][mapY] != 0) && (!movingTile))
							{
								if ((!facingSide) && (rayDirY > 0) && (worldPushable[mapX][mapY] == 1) && (posX > mapX))
								{
									movingTile=10;
									pushedTileX=mapX;
									pushedTileY=mapY;
									pushedTileDir=1;
									worldPushable[mapX][mapY]=0;
									worldDiscovered[mapX][mapY]=0;
									nbPushed++;
								}

								if ((facingSide) && (rayDirX > 0) && (worldPushable[mapX][mapY] == 2) && (posY < mapY))
								{
									movingTile=10;
									pushedTileX=mapX;
									pushedTileY=mapY;
									pushedTileDir=2;
									worldPushable[mapX][mapY]=0;
									worldDiscovered[mapX][mapY]=0;
									nbPushed++;
								}

								if ((!facingSide) && (rayDirY < 0) && (worldPushable[mapX][mapY] == 3) && (posX < mapX))
								{
									movingTile=10;
									pushedTileX=mapX;
									pushedTileY=mapY;
									pushedTileDir=3;
									worldPushable[mapX][mapY]=0;
									worldDiscovered[mapX][mapY]=0;
									nbPushed++;
								}

								if ((facingSide) && (rayDirX < 0) && (worldPushable[mapX][mapY] == 4) && (posY > mapY))
								{
									movingTile=10;
									pushedTileX=mapX;
									pushedTileY=mapY;
									pushedTileDir=4;
									worldPushable[mapX][mapY]=0;
									worldDiscovered[mapX][mapY]=0;
									nbPushed++;
								}
							}
							else
							{
								messagetime=360;
								messageno=facingTexture;
								if (messageno_s) messageno_s=-1;
							}

						}

					}

					if (movingTile > 0) movingTile--; else pushedTileDir=0;
					if ((movingTile%5) == 4)
					{
						if (movingTile == 9) oslPlaySound(rumble, 6);

						switch(pushedTileDir)
						{
							case 1:
							worldMap[pushedTileX-1][pushedTileY] = worldMap[pushedTileX][pushedTileY];
							worldMap[pushedTileX][pushedTileY]=0;
							worldDiscovered[pushedTileX][pushedTileY]=0;
							pushedTileX--;
							break;

							case 2:
							worldMap[pushedTileX][pushedTileY+1] = worldMap[pushedTileX][pushedTileY];
							worldMap[pushedTileX][pushedTileY]=0;
							worldDiscovered[pushedTileX][pushedTileY]=0;
							pushedTileY++;
							break;

							case 3:
							worldMap[pushedTileX+1][pushedTileY] = worldMap[pushedTileX][pushedTileY];
							worldMap[pushedTileX][pushedTileY]=0;
							worldDiscovered[pushedTileX][pushedTileY]=0;
							pushedTileX++;
							break;

							case 4:
							worldMap[pushedTileX][pushedTileY-1] = worldMap[pushedTileX][pushedTileY];
							worldMap[pushedTileX][pushedTileY]=0;
							worldDiscovered[pushedTileX][pushedTileY]=0;
							pushedTileY--;
							break;
						}
					}
					//move forward if no wall in front of you
					if (!isCredits)
					{
						if ((osl_keys -> pressed.cross) || (osl_keys -> held.cross))
						{
							if ((weapon) && (!isCredits))
							{
								if (ammo)
								{
									//if the sprite is "alive", visible (not hidden by a wall, or facing him) and not hitting a transparent pixel
									if ((((weapon == 1) && (osl_keys -> pressed.cross)) || ((weapon > 1) && (osl_keys -> held.cross))) && (!frameshot))
									{
										if (((facingSprite == 192) || (facingSprite == 194) || (facingSprite == 193)) && (visibleSprite[facingSpriteNumber]) && (sprChunk))
										{
											if (!frameshot) sprite[facingSpriteNumber].health -= (weapon) * (((int)(-1.2578616352201*distToSprite + 25.125786163522)) <= 0)?2:((int)(-1.2578616352201*distToSprite + 25.125786163522));

											if (sprite[facingSpriteNumber].health <= 0)
											{
												sprite[facingSpriteNumber].texture = 195;
												sprite[facingSpriteNumber].wokenUp = 24;
												oslStopSound(dying);
												oslPlaySound(dying, 2);
												nbKilled++;
											}
											else
											{
												sprite[facingSpriteNumber].stunned = 4;
												sprite[facingSpriteNumber].texture = 194;
											}

										}

										if (((facingSprite == 197) || (facingSprite == 198) || (facingSprite == 199)) && (visibleSprite[facingSpriteNumber]) && (sprChunk))
										{
											if (!frameshot) sprite[facingSpriteNumber].health -= (weapon) * (((int)(-1.2578616352201*distToSprite + 25.125786163522)) <= 0)?2+random(4):((int)(-1.2578616352201*distToSprite + 25.125786163522));

											if (sprite[facingSpriteNumber].health <= 0)
											{
												sprite[facingSpriteNumber].texture = 200;
												sprite[facingSpriteNumber].wokenUp = 24;
												oslStopSound(dying);
												oslPlaySound(dying, 2);
												nbKilled++;
											}
											else
											{
												sprite[facingSpriteNumber].stunned = 4;
												sprite[facingSpriteNumber].texture = 199;
											}

										}

										if (((facingSprite == 202) || (facingSprite == 203) || (facingSprite == 204)) && (visibleSprite[facingSpriteNumber]) && (sprChunk))
										{
											if (!frameshot) sprite[facingSpriteNumber].health -= (weapon) * (((int)(-1.2578616352201*distToSprite + 25.125786163522)) <= 0)?2+random(4):((int)(-1.2578616352201*distToSprite + 25.125786163522));

											if (sprite[facingSpriteNumber].health <= 0)
											{
												sprite[facingSpriteNumber].texture = 205;
												sprite[facingSpriteNumber].wokenUp = 24;
												oslStopSound(dying);
												oslPlaySound(dying, 2);
												nbKilled++;
											}
											else
											{
												sprite[facingSpriteNumber].stunned = 4;
												sprite[facingSpriteNumber].texture = 204;
											}

										}

										if (((facingSprite == 207) || (facingSprite == 208) || (facingSprite == 209)) && (visibleSprite[facingSpriteNumber]) && (sprChunk))
										{
											if (!frameshot) sprite[facingSpriteNumber].health -= (weapon) * (random(2)+4);

											if (sprite[facingSpriteNumber].health <= 0)
											{
												sprite[facingSpriteNumber].texture = 210;
												sprite[facingSpriteNumber].wokenUp = 24;
												oslPlaySound(b1_die, 2);
												nbKilled++;
											}
											else
											{
												oslPlaySound(b1_hurt, 2);
											}

										}

										if (!frameshot)
										{
											if ((weapon==1) && (weaponY==0) && (osl_keys -> pressed.cross))
											{
												weaponY=16;
												frameshot=12;
												oslPlaySound(weapon_shoot, 6);
												ammo--;
											}

											if ((weapon==2) && (weaponY==0) && (osl_keys -> held.cross))
											{
												weaponY=16;
												frameshot=12;
												oslPlaySound(shotgun, 6);
												ammo--;
											}

											if ((weapon==3) && (weaponY==0) && (osl_keys -> held.cross))
											{
												weaponY=16;
												frameshot=2;
												oslPlaySound(machinegun, 6);
												ammo--;
											}
										}

										if (!ammo)
										{
											weapon=0;
											weaponY=-96;
										}
									}
								}
								else
								{
									if (osl_keys -> pressed.cross) oslPlaySound(weapon_click, 6);
								}
							}
							else
							{
								if ((osl_keys -> pressed.cross))
								{
									oslPlaySound(knifing, 6);
									weaponY=16;

									if (((facingSprite == 192) || (facingSprite == 194) || (facingSprite == 193)) && (visibleSprite[facingSpriteNumber]) && (distToSprite <= 0.33))
									{
										sprite[facingSpriteNumber].health -= -91.304347826087*distToSprite + 39.130434782609;

										if (sprite[facingSpriteNumber].health <= 0)
										{
											sprite[facingSpriteNumber].texture = 195;
											sprite[facingSpriteNumber].wokenUp = 24;
											oslPlaySound(dying, 7);
										}
										else
										{
											sprite[facingSpriteNumber].stunned = 4;
											sprite[facingSpriteNumber].texture = 194;
										}
									}

									if (((facingSprite == 197) || (facingSprite == 198) || (facingSprite == 199)) && (visibleSprite[facingSpriteNumber]) && (distToSprite <= 0.33))
									{
										sprite[facingSpriteNumber].health -= -91.304347826087*distToSprite + 39.130434782609;

										if (sprite[facingSpriteNumber].health <= 0)
										{
											sprite[facingSpriteNumber].texture = 200;
											sprite[facingSpriteNumber].wokenUp = 24;
											oslPlaySound(dying, 7);
										}
										else
										{
											sprite[facingSpriteNumber].stunned = 4;
											sprite[facingSpriteNumber].texture = 199;
										}
									}

									if (((facingSprite == 202) || (facingSprite == 203) || (facingSprite == 204)) && (visibleSprite[facingSpriteNumber]) && (distToSprite <= 0.33))
									{
										sprite[facingSpriteNumber].health -= -91.304347826087*distToSprite + 39.130434782609;

										if (sprite[facingSpriteNumber].health <= 0)
										{
											sprite[facingSpriteNumber].texture = 205;
											sprite[facingSpriteNumber].wokenUp = 24;
											oslPlaySound(dying, 7);
										}
										else
										{
											sprite[facingSpriteNumber].stunned = 4;
											sprite[facingSpriteNumber].texture = 204;
										}
									}

									//207, 208, 209? NOPE! It's a boss! Knifing him will do nothing!

								}

							}
						}

						if ((osl_keys -> pressed.select) && (doorTrans < 1))
						{
							weaponY = -96;
							weapon++;
							weapon=weapon%4;

							while (weaponPossessed[weapon] == 0)
							{
								weapon++;
								weapon=weapon%4;
							}
						}

						if ((osl_keys -> pressed.right) && (doorTrans < 1))
						{
							uTurn = 22;
						}

						if (((osl_pad.analogY < -16)) && (doorTrans < 1) && (distToFacingTex >= 0.1))
						{
						  coeff=abs(osl_pad.analogY)/16;
						  if(!(worldMap[(int)(posX + dirX * moveSpeed * coeff)][(int)(posY)])) posX += dirX * moveSpeed * coeff;
						  if(!(worldMap[(int)(posX)][(int)(posY + dirY * moveSpeed * coeff)])) posY += dirY * moveSpeed * coeff;
						}
						//move backwards if no wall behind you
						if (((osl_pad.analogY > 16)) && (doorTrans < 1))
						{
						  coeff=abs(osl_pad.analogY)/16;
						  if(!(worldMap[(int)(posX - dirX * moveSpeed * coeff)][(int)(posY)])) posX -= dirX * moveSpeed * coeff;
						  if(!(worldMap[(int)(posX)][(int)(posY - dirY * moveSpeed * coeff)])) posY -= dirY * moveSpeed * coeff;
						}

						if ((osl_keys->held.R) && (doorTrans < 1))
						{
						  coeff=8;
						  if(!(worldMap[(int)(posX + planeX * moveSpeed * coeff)][(int)(posY)])) posX += planeX * moveSpeed * coeff;
						  if(!(worldMap[(int)(posX)][(int)(posY + planeY * moveSpeed * coeff)])) posY += planeY * moveSpeed * coeff;
						}

						if ((osl_keys->held.L) && (doorTrans < 1))
						{
						  coeff=8;
						  if(!(worldMap[(int)(posX - planeX * moveSpeed * coeff)][(int)(posY)])) posX -= planeX * moveSpeed * coeff;
						  if(!(worldMap[(int)(posX)][(int)(posY - planeY * moveSpeed * coeff)])) posY -= planeY * moveSpeed * coeff;
						}

						//rotate to the right
						if (((osl_pad.analogX > 16)) && (!uTurn))
						{
						  coeff=abs(osl_pad.analogX)/16;
						  //both camera direction and camera plane must be rotated
						  oldDirX = dirX;
						  dirX = dirX * vfpu_cosf(-rotSpeed * coeff) - dirY * vfpu_sinf(-rotSpeed * coeff);
						  dirY = oldDirX * vfpu_sinf(-rotSpeed * coeff) + dirY * vfpu_cosf(-rotSpeed * coeff);
						  oldPlaneX = planeX;
						  planeX = planeX * vfpu_cosf(-rotSpeed * coeff) - planeY * vfpu_sinf(-rotSpeed * coeff);
						  planeY = oldPlaneX * vfpu_sinf(-rotSpeed * coeff) + planeY * vfpu_cosf(-rotSpeed * coeff);

						}
						//rotate to the left
						if (((osl_pad.analogX < -16)) && (!uTurn))
						{
						  coeff=abs(osl_pad.analogX)/16;
						  //both camera direction and camera plane must be rotated
						  oldDirX = dirX;
						  dirX = dirX * vfpu_cosf(rotSpeed * coeff) - dirY * vfpu_sinf(rotSpeed * coeff);
						  dirY = oldDirX * vfpu_sinf(rotSpeed * coeff) + dirY * vfpu_cosf(rotSpeed * coeff);
						  oldPlaneX = planeX;
						  planeX = planeX * vfpu_cosf(rotSpeed * coeff) - planeY * vfpu_sinf(rotSpeed * coeff);
						  planeY = oldPlaneX * vfpu_sinf(rotSpeed * coeff) + planeY * vfpu_cosf(rotSpeed * coeff);
						}
					}
					else
					{
						if ((frame%600 >= 510))
						{
							  rotSpeed=0.01745;
							  oldDirX = dirX;
							  dirX = dirX * vfpu_cosf(-rotSpeed) - dirY * vfpu_sinf(-rotSpeed);
							  dirY = oldDirX * vfpu_sinf(-rotSpeed) + dirY * vfpu_cosf(-rotSpeed);
							  oldPlaneX = planeX;
							  planeX = planeX * vfpu_cosf(-rotSpeed) - planeY * vfpu_sinf(-rotSpeed);
							  planeY = oldPlaneX * vfpu_sinf(-rotSpeed) + planeY * vfpu_cosf(-rotSpeed);
						}
						if (frame == 2400) frame=0;
					}

					if (uTurn)
					{
						  oldDirX = dirX;
						  dirX = dirX * vfpu_cosf(-0.150) - dirY * vfpu_sinf(-0.150);
						  dirY = oldDirX * vfpu_sinf(-0.150) + dirY * vfpu_cosf(-0.150);
						  oldPlaneX = planeX;
						  planeX = planeX * vfpu_cosf(-0.150) - planeY * vfpu_sinf(-0.150);
						  planeY = oldPlaneX * vfpu_sinf(-0.150) + planeY * vfpu_cosf(-0.150);
						  uTurn--;
					}

					if ((osl_pad.analogY > -16) && (osl_pad.analogY < 16) && (osl_pad.analogX < 16) && (osl_pad.analogX > -16))
					{
						bobbing=0.025;
					}
					else
					{
						bobbing=0.05*coeff/3;
						if ((osl_keys->held.R) || (osl_keys->held.L))
						{
							bobbing = 0.05 * 8;
						}
					}

					for(i=0; i<MAXSPRITES; i++)
					{
						/*if ((!(sprite[i].wokenUp)) && (sprite[i].health > 0))
						{
							if ((sprite[i].texture == 197) || (sprite[i].texture == 199))
							{
								sprite[i].texture = 198;
								if (sprite[i].wokenUp > 24) sprite[i].wokenUp = 24;
							}
						}*/
						spritePosX=pspFpuFloor(sprite[i].x);
						spritePosY=pspFpuFloor(sprite[i].y);

						if (((sprite[i].texture >= 192) && (sprite[i].texture != 196) && (sprite[i].texture != 201) && (sprite[i].texture != 206))) spriteDiscovered[spritePosX][spritePosY]=0;

						if ((sprite[i].wokenUp) && (sprite[i].health > 0) && (sprite[i].discovered))
						{
							j=((posX - sprite[i].x) * (posX - sprite[i].x) + (posY - sprite[i].y) * (posY - sprite[i].y));

							if (j >= 0.33)
							{
								if ((sprite[i].texture != 198) && (sprite[i].texture != 203) && (sprite[i].texture != 208))
								{
										if (sprite[i].x > posX)
										{
											if (worldMap[(int)(pspFpuFloor(sprite[i].x-0.50))][(int)(pspFpuFloor(sprite[i].y))] == 0) sprite[i].x -= sprite[i].speed;
										}
										else if (sprite[i].x < posX)
										{
											if (worldMap[(int)(pspFpuFloor(sprite[i].x+0.50))][(int)(pspFpuFloor(sprite[i].y))] == 0) sprite[i].x += sprite[i].speed;
											if (sprite[i].x > posX) sprite[i].x = posX;
										}

										if (sprite[i].y > posY)
										{
											if (worldMap[(int)(pspFpuFloor(sprite[i].x))][(int)(pspFpuFloor(sprite[i].y-0.50))] == 0) sprite[i].y -= sprite[i].speed;
										}
										else if (sprite[i].y < posY)
										{
											if (worldMap[(int)(pspFpuFloor(sprite[i].x))][(int)(pspFpuFloor(sprite[i].y+0.50))] == 0) sprite[i].y += sprite[i].speed;
											if (sprite[i].y > posY) sprite[i].y = posY;
										}
								}
							}
							else
							{
								if ((sprite[i].texture == 192) || (sprite[i].texture == 194))
								{
									sprite[i].texture = 193;
									if (sprite[i].wokenUp > 24) sprite[i].wokenUp = 24;
								}

								if ((sprite[i].texture == 197) || (sprite[i].texture == 199))
								{
									sprite[i].texture = 198;
									if (sprite[i].wokenUp > 24) sprite[i].wokenUp = 24;
								}

								if ((sprite[i].texture == 202) || (sprite[i].texture == 204))
								{
									sprite[i].texture = 203;
									if (sprite[i].wokenUp > 24) sprite[i].wokenUp = 24;
								}

								if ((sprite[i].texture == 208) || (sprite[i].texture == 209))
								{
									sprite[i].texture = 208;
									if (sprite[i].wokenUp > 24) sprite[i].wokenUp = 24;
								}
							}
						}

						if (sprite[i].stunned > 0)
						{
							sprite[i].stunned--;
						}
						else
						{
							switch(sprite[i].texture)
							{
								case 194:
									sprite[i].texture=192;
								break;

								case 199:
									sprite[i].texture=197;
								break;

								case 204:
									sprite[i].texture=202;
								break;

								case 209:
									sprite[i].texture=207;
								break;
							}
						}

						if (sprite[i].wokenUp > 0)
						{
							if (((sprite[i].texture == 195) || (sprite[i].texture == 200)) && (sprite[i].wokenUp == 1))
							{
								oslStopSound(dying);
								for (k=0; k<nbSprites; k++)
								{
									if (random(601) < 4)
									{
										if (sprite[k].x == -1)
										{
											sprite[k].x = sprite[i].x+0.25;
											sprite[k].y = sprite[i].y-0.25;
											sprite[k].texture = 132+random(2);
											if (nbSprites < MAXSPRITES) nbSprites++;
											break;
										}
									}
								}
							}

							if ((sprite[i].texture == 200) && (sprite[i].wokenUp == 1))
							{
								oslStopSound(dying);
								for (k=0; k<nbSprites; k++)
								{
									if (random(100) < 90)
									{
										if (sprite[k].x == -1)
										{
											sprite[k].x = sprite[i].x-0.25;
											sprite[k].y = sprite[i].y+0.25;
											sprite[k].texture = 130;
											if (nbSprites < MAXSPRITES) nbSprites++;
											break;
										}
									}
								}
							}

							if ((sprite[i].texture == 205) && (sprite[i].wokenUp == 1))
							{
								oslStopSound(dying);
								for (k=0; k<nbSprites; k++)
								{
									if (random(100) < 80)
									{
										if (sprite[k].x == -1)
										{
											sprite[k].x = sprite[i].x-0.25;
											sprite[k].y = sprite[i].y+0.25;
											sprite[k].texture = 130;
											if (nbSprites < MAXSPRITES) nbSprites++;
											break;
										}
									}
									else
									{
										if (sprite[k].x == -1)
										{
											sprite[k].x = sprite[i].x-0.25;
											sprite[k].y = sprite[i].y+0.25;
											sprite[k].texture = 134;
											if (nbSprites < MAXSPRITES) nbSprites++;
											break;
										}
									}
								}
							}

							if ((sprite[i].texture == 210) && (sprite[i].wokenUp == 1))
							{
								oslStopSound(dying);
								for (k=0; k<nbSprites; k++)
								{
									if (sprite[k].x == -1)
									{
										sprite[k].x = sprite[i].x-0.25;
										sprite[k].y = sprite[i].y+0.25;
										sprite[k].texture = 138;
										if (nbSprites < MAXSPRITES) nbSprites++;
										break;
									}
								}
							}



							if ((sprite[i].texture == 193) && (sprite[i].wokenUp == 12) && (distToSprite < 0.33))
							{
									oslPlaySound(shovel, 4);
									health -= (-15.625*distToSprite + 11.15625);
									oslStartDrawing();
									oslSetDrawBuffer(OSL_SECONDARY_BUFFER);
									oslDrawFillRect(0,0,480,272, RGB(255, 0, 0));
									oslEndDrawing();
									oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
							}

							if ((sprite[i].texture == 198) && (sprite[i].wokenUp%32 == 12))
							{

								if (visibleSprite[i])
								{
									oslPlaySound(weapon_shoot, 4);
								}

								if ((visibleSprite[i]) && (facingSprite == 198))
								{
									k=(int)((-1.98*distToSprite + 50.65)/1.66);
									if (k <= 0)
									{
										k=random(3)+2;
									}

									if (armor)
									{
										if (armor-k < 0)
										{
											k -= armor;
											armor=0;
											health -= k;
											oslPlaySound(worn_out, 2);
										}
										else
										{
											armor -= k;
											if (!armor) oslPlaySound(worn_out, 2);
										}
									}
									else
									{
										health -= k;
									}

									oslStartDrawing();
									oslSetDrawBuffer(OSL_SECONDARY_BUFFER);
									oslDrawFillRect(0,0,480,272, RGB(255, 0, 0));
									oslEndDrawing();
									oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
								}
							}

							if ((sprite[i].texture == 203) && (sprite[i].wokenUp%8 == 4))
							{

								if (visibleSprite[i])
								{
									oslPlaySound(shotgun, 4);
								}

								if ((visibleSprite[i]) && (facingSprite == 203))
								{
									k=(int)((-1.98*distToSprite + 50.65)/6);
									if (k <= 0)
									{
										k=random(3)+2;
									}

									if (armor)
									{
										if (armor-k < 0)
										{
											k -= armor;
											armor=0;
											health -= k;
										}
										else
										{
											armor -= k;
										}
									}
									else
									{
										health -= k;
									}

									oslStartDrawing();
									oslSetDrawBuffer(OSL_SECONDARY_BUFFER);
									oslDrawFillRect(0,0,480,272, RGB(255, 0, 0));
									oslEndDrawing();
									oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
								}
							}

							if ((sprite[i].texture == 208) && (sprite[i].wokenUp%8 == 4))
							{

								if (visibleSprite[i])
								{
									oslPlaySound(machinegun, 4);
								}
								else
								{
									sprite[i].texture = 207;
									sprite[i].wokenUp = 64;
								}

								if ((visibleSprite[i]) && (facingSprite == 208))
								{
									k=(int)((-1.98*distToSprite + 50.65));
									if (k <= 0)
									{
										k=random(3)+2;
									}

									if (armor)
									{
										if (armor-k < 0)
										{
											k -= armor;
											armor=0;
											health -= k;
										}
										else
										{
											armor -= k;
										}
									}
									else
									{
										health -= k;
									}

									oslStartDrawing();
									oslSetDrawBuffer(OSL_SECONDARY_BUFFER);
									oslDrawFillRect(0,0,480,272, RGB(255, 0, 0));
									oslEndDrawing();
									oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
								}
							}


							if (sprite[i].stunned == 0)
							{
								sprite[i].wokenUp--;
							}
						}
						else
						{
							switch(sprite[i].texture)
							{
								case 193:
									sprite[i].texture=192;
									sprite[i].wokenUp=501;
								break;

								case 195:
									sprite[i].texture=196;
								break;

								case 197:
									if  (distToSprite < 25)
									{
										sprite[i].texture=198;
										sprite[i].wokenUp=24;
									}
								break;

								case 198:
									sprite[i].texture=197;
									sprite[i].wokenUp=64;
								break;

								case 200:
									sprite[i].texture=201;
								break;

								case 202:
									if  (distToSprite < 25)
									{
										sprite[i].texture=203;
										sprite[i].wokenUp=24;
									}
								break;

								case 203:
									sprite[i].texture=202;
									sprite[i].wokenUp=64;
								break;

								case 205:
									sprite[i].texture=206;
									sprite[i].wokenUp=0;
								break;

								case 207:
									if  (distToSprite < 25)
									{
										sprite[i].texture=208;
										sprite[i].wokenUp=24;
									}
								break;

								case 208:
									sprite[i].texture=208;
									sprite[i].wokenUp=24;
								break;

								case 210:
									sprite[i].texture=211;
									sprite[i].wokenUp=0;
								break;


							}
						}
					}
				}
	  	  }
	  }


  frame=0;
  while((oslGetSoundChannel(endlevel) == 7) && (frame < 120))
  {
	  frame++;
	  oslWaitVSync();
  }

  fadeout(RGB(0, 0, 0));

  oslDeleteImage(amiga);

  for (i=0; i<4; i++)
  {
	  oslDeleteImage(weapons[i]);
  }

  oslDeleteImage(weapon_fire);
  oslDeleteImage(bullet);
  oslDeleteImage(sidedoor);
  oslDeleteImage(minikeys);

  oslDeleteImage(texture[0][0]);
  oslDeleteImage(texture[0][1]);

  for (i=1; i<256; i++)
	{
	  if (recensedTextures[i] > 0)
	  {
		  oslDeleteImage(texture[i][0]);
		  oslDeleteImage(texture[i][1]);
	  }
	}

  oslDeleteImage(hand);
  oslDeleteImage(texpspFpuFloor);

  oslDeleteImage(sprs[0]);

  for (i=1; i<256; i++)
	{
	  if (recensedSprites[i] > 0) oslDeleteImage(sprs[i]);
	}

  oslDeleteImage(sky);
  oslDeleteImage(coin);
  oslDeleteImage(digits);
  oslDeleteImage(sfresh);
  oslDeleteImage(armor_icon);

  oslDeleteSound(wolfen);
  oslDeleteSound(uhcakip);
  oslDeleteSound(rumble);
  oslDeleteSound(enemy);
  oslDeleteSound(weapon_shoot);
  oslDeleteSound(shovel);

  oslDeleteSound(dying);
  oslDeleteSound(weapon_click);
  oslDeleteSound(load);
  oslDeleteSound(aah);

  oslDeleteSound(urdead);

  oslDeleteSound(endlevel);

  oslDeleteSound(knifing);
  oslDeleteSound(grunt);
  oslDeleteSound(shotgun);

  oslDeleteSound(vomit);
  oslDeleteSound(coins_sound);
  oslDeleteSound(gulp);
  oslDeleteSound(machinegun);

  oslDeleteSound(got_mg);
  oslDeleteSound(got_sg);

  oslDeleteSound(huhaha);

  oslDeleteSound(seeknd);
  oslDeleteSound(b1_die);
  oslDeleteSound(b1_hurt);
  oslDeleteSound(boiling);
  oslDeleteSound(door_open);
  oslDeleteSound(door_close);
  oslDeleteSound(supercharge);
  oslDeleteSound(worn_out);

  for (i=0; i<256; i++) recensedTextures[i]=0;

  if (deathcause == 3)
  {
	  oslStartDrawing();
	  oslDrawFillRect(0, 0, 480, 272, RGB(0, 0, 0));
	  sprintf(path_buffer,"Enemies killed: %d %%",(int)((nbEnemies>0)?(float)(nbKilled*100/nbEnemies):100));
	  center(120, path_buffer, RGB(255, 255, 255));

	  sprintf(path_buffer,"Secrets discovered: %d %%",(int)((nbSecrets>0)?(float)(nbPushed*100/nbSecrets):100));
	  center(160, path_buffer, RGB(255, 255, 255));

	  oslEndDrawing();
	  oslSwapBuffers();
	  oslWaitKey();
  }

  return deathcause;
}

void end_episode(int ep)
{
	int frame=0, quit=0;

	OSL_IMAGE *bg_endep = oslLoadImageFilePNG("./gfx/bg_endep.png",OSL_IN_RAM, OSL_PF_5551);

    /*fonts[0] = oslLoadFontFile("gfx/nokia.oft");
    fonts[1] = oslLoadFontFile("gfx/amstrad.oft");
    fonts[2] = oslLoadFontFile("gfx/gothic.oft");*/

	while (!quit)
	{
		oslStartDrawing();

		oslSetImageTileSize(bg_endep, 0, 0, 480, 272);
		spr_draw(bg_endep, 0, 0);

		switch(ep)
		{
			case 0:
				oslSetFont(fonts[1]);
				center(8, "THE FIRST ACT IS COMPLETED.", RGB(255, 0, 0));

				oslSetFont(fonts[2]);
				center(32, "You have defeated the big black baron of machine guns.", RGB(255, 255, 255));

				center(56, "As you process into the backrooms, you then find a computer on", RGB(255, 255, 255));
				center(68, "which an email was sent from somewhere else at the COGEEP.", RGB(255, 255, 255));
				center(92, "\"I hope that the so-called hero has been neutralized.\"", RGB(255, 255, 0));
				center(116, "A surge of anger rises into you and you reply immediately:", RGB(255, 255, 255));
				center(140, "\"No, I am alive, and I will definitely make you pay for the damage", RGB(0, 255, 255));
				center(152, "you have done on Easter!\"", RGB(0, 255, 255));

				center(176, "The anonymous correspondent replies:", RGB(255, 255, 255));
				center(188, "\"Oh, I see. Let's meet at our botanical gardens.\"", RGB(255, 255, 0));

				center(212, "With the feeling that another obvious trap has been set,", RGB(255, 255, 255));
				center(224, "you leave for the gardens anyway.", RGB(255, 255, 255));
			break;
		}

		if (frame < 272)
		{
			oslSetImageTileSize(bg_endep, 0, frame, 480, 272);
			spr_draw(bg_endep, 0, frame);
		}

		oslSetFont(fonts[1]);
		center(260, "PRESS ANY KEY TO CONTINUE.", RGBA(255, 128, 0, (int)(127+128*vfpu_sinf(0.05*frame+128))));

		oslEndDrawing();
		oslSwapBuffers();

		frame++;

		if (oslKbhit()) quit=1;
	}

	oslDeleteImage(bg_endep);
	fadeout(RGB(0, 0, 0));

	oslSetFont(fonts[0]);
}


void sandbox(int what)
{
	int j;
	char *path_buffer;
	SceUID checkfile;

	if (what==1)
	{
		path_buffer="*** UYSLGDHFKUJQLSDGH !";
		j=strlen(path_buffer);

		checkfile = sceIoOpen("./something.txt", PSP_O_WRONLY|PSP_O_CREAT, 0777);

		sceIoWrite(checkfile, path_buffer, j);

		sceIoClose(checkfile);
	}

}

int main()
{
	SceUID check;
	const char *items[5]={"New Game", "Level Editor", "Options", "About…", "Quit"};
	const char *eps_names[3]={"First Brutal Layoffs", "Death by Environment", "The CEO makes it"};
	const char *diffs_names[4]={"Hey, I'm just an intern!", "Guess my trial period is over.", "Don't call me a \"junior\" again.", "You are all FIRED!"};
	char music_path[30];

	int i, j, k, quit=0, chm=0, frame=0, ep=0, chd=0, chl=0;
	int floatings[24][4];

	int options[9]={1, 480, 272, 1, 0, 1, 0, 0, 100};

	short JustTriggeringAWarningLol=3;

	Sprite * sprite;

	OSL_IMAGE *hand, *logo, *logo_trans, *epimg[3], *choose_ep, *choose_df, *pringle;
	OSL_SOUND *theme;

    //Initialisation de la librairie

	SetupCallbacks();
	sceKernelUtilsMt19937Init(&ctx, time(NULL));
	scePowerSetClockFrequency(333, 333, 166);

	oslInit(0);
    oslInitGfx(_16bit, 1);
    oslInitAudio();
    oslInitAudioME(OSL_FMT_ALL);


    oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
    oslSetAlpha(OSL_FX_DEFAULT,0);

    fonts[0] = oslLoadFontFile("gfx/nokia.oft");
    fonts[1] = oslLoadFontFile("gfx/amstrad.oft");
    fonts[2] = oslLoadFontFile("gfx/gothic.oft");

    hand = oslLoadImageFilePNG("./gfx/hand.png",OSL_IN_RAM, OSL_PF_5551);
    logo = oslLoadImageFilePNG("./gfx/logo.png",OSL_IN_RAM, OSL_PF_5551);
    logo_trans = oslLoadImageFilePNG("./gfx/logo_trans.png",OSL_IN_RAM, OSL_PF_5551);

    epimg[0] = oslLoadImageFilePNG("./gfx/ep0.png",OSL_IN_RAM, OSL_PF_5551);
    epimg[1] = oslLoadImageFilePNG("./gfx/ep1.png",OSL_IN_RAM, OSL_PF_5551);
    epimg[2] = oslLoadImageFilePNG("./gfx/ep2.png",OSL_IN_RAM, OSL_PF_5551);

    pringle = oslLoadImageFilePNG("./gfx/pringle.png",OSL_IN_RAM, OSL_PF_5551);

    choose_ep = oslLoadImageFilePNG("./gfx/choose_ep.png",OSL_IN_RAM, OSL_PF_5551);
    choose_df = oslLoadImageFilePNG("./gfx/choose_df.png",OSL_IN_RAM, OSL_PF_5551);

    theme = oslLoadSoundFileMOD("./mzx/theme.xm", OSL_FMT_NONE);
    worldMap[0][0]=-1;

    check = sceIoDopen("flash1:/");				//Detecting PPSSPP
    if (check < 0) options[0]=1; else options[0]=2;	//If Flash1 not found, that means you're using an emulator and we're going to use HIGH quality, or else MEDIUM quality
    sceIoDclose(check);

	oslSetTransparentColor(RGB(255,0,255));
	oslSetBkColor(RGB(255,0,255));

    rndsft();

	theme -> volumeLeft = 163.84 * options[8];
    theme -> volumeRight = 163.84 * options[8];

	for (i=0; i<mapWidth; i++)
	{
		for (j=0; j<mapHeight; j++)
		{
			worldSprites[i][j]=0;
			worldVendings[i][j]=0;
			worldPushable[i][j]=0;
			worldDiffs[i][j]=0;
		}
	}

	for (i=0; i<24; i++)
	{
		floatings[i][0]=(random(2)?-1:1);
		floatings[i][1]=floatings[i][0]*random(480);
		floatings[i][2]=random(208);
		floatings[i][3]=random(300)+60;
	}

	oslPlaySound(theme, 0);

    while (!quit)
    {
    	j=0;
    	frame++;


		oslStartDrawing();
		oslDrawFillRect(0, 0, 480, 272, RGB(22, 58, 68));

		oslSetAlpha(OSL_FX_TINT, RGBA(0, 0, 0, 32));
		oslSetBilinearFilter(1);

		for (i=0; i<24; i++)
		{
			logo_trans -> stretchX = floatings[i][3];
			logo_trans -> stretchY = ((int)floatings[i][3]/3.75);
			spr_draw(logo_trans, floatings[i][1], floatings[i][2]);

			if (floatings[i][0] == 1)
			{
				floatings[i][1]--;
				if (floatings[i][1] == -1*floatings[i][3])
				{
					floatings[i][0]=(random(2)?-1:1);
					floatings[i][1]=floatings[i][0]*(480);
					floatings[i][2]=random(208);
					floatings[i][3]=random(300)+60;
				}
			}
			else
			{
				floatings[i][1]++;
				if (floatings[i][1] == 480)
				{
					floatings[i][0]=(random(2)?-1:1);
					floatings[i][1]=floatings[i][0]*480;
					floatings[i][2]=random(208);
					floatings[i][3]=random(240)+64;
				}
			}
		}

		oslSetBilinearFilter(0);
		oslSetAlpha(OSL_FX_DEFAULT, 0);

		oslDrawFillRect(120, 100, 360, 224, RGB(0, 0, 0));
		oslDrawFillRect(0, 16, 480, 48, RGB(11, 26, 34));

		oslDrawLine(360, 100, 360, 224, RGB(44, 116, 136));
		oslDrawLine(120, 224, 360, 224, RGB(44, 116, 136));
		oslDrawLine(120, 100, 120, 224, RGB(11, 26, 34));
		oslDrawLine(120, 100, 360, 100, RGB(11, 26, 34));

		spr_draw(logo, 120, 8);

		oslSetTextColor(RGB(255, 255, 255));
		oslSetFont(fonts[1]);


		for (i=0; i<5; i++)
		{
			oslDrawString(200, 108+i*24, items[i]);
		}

		oslSetFont(fonts[0]);
		center(256, "Copyleft 2015-2016 by 240-185", RGB(255, 255, 128));


		oslSetAlpha(OSL_FX_ALPHA, 127+128*vfpu_sinf(0.0375*frame));
		spr_draw(hand, 160, 110+chm*24);

		oslSetAlpha(OSL_FX_DEFAULT, 0);
		if (frame < 256) oslDrawFillRect(0, 0, 480, 272, RGBA(0, 0, 0, 256-frame));

		oslEndDrawing();
		oslSwapBuffers();
		oslWaitVSync();

		oslReadKeys();

		if ((osl_keys->pressed.up) && (chm > 0))
		{
			chm--;
		}
		if ((osl_keys->pressed.down) && (chm < 4))
		{
			chm++;
		}

		if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
		{
			fadeout(RGB(0,0,0));
			oslSetFont(fonts[0]);

			switch(chm)
			{
				case 0:

					if (osl_keys->held.L)
					{
						chl=loadLevel_UI();
						j=0;
						frame=0;
					}
					else
					{
						ep=0;
						j=0;
						frame=0;


						while (!j)
						{
							oslStartDrawing();
							oslDrawFillRect(0, 0, 480, 272, RGB(22, 58, 68));

							oslDrawFillRect(120, 100, 360, 224, RGB(0, 0, 0));
							oslDrawFillRect(0, 16, 480, 48, RGB(11, 26, 34));

							spr_draw(choose_ep, 120, 8);

							oslDrawLine(360, 100, 360, 224, RGB(44, 116, 136));
							oslDrawLine(120, 224, 360, 224, RGB(44, 116, 136));
							oslDrawLine(120, 100, 120, 224, RGB(11, 26, 34));
							oslDrawLine(120, 100, 360, 100, RGB(11, 26, 34));

							oslDrawFillRect(122, 106+ep*40, 358, 142+ep*40, RGBA(11, 26, 34,(int)(127+128*vfpu_sinf(0.05*frame+128))));

							for (i=0; i<3; i++)
							{
								spr_draw(epimg[i], 124, 108+i*40);
								oslSetFont(fonts[0]);
								sprintf(music_path, "Episode %d", i+1);
								oslSetTextColor(RGB(255, 255, 0));
								oslDrawString(196, 108+i*40, music_path);
								oslSetFont(fonts[1]);
								oslSetTextColor(RGB(255, 255, 255));
								oslDrawString(196, 122+i*40, eps_names[i]);
								switch (i)
								{
									case 2:
									oslDrawString(196, 130+i*40, "personal");
								}
							}

							oslSetFont(fonts[0]);
							center(258, "UP or DOWN to select, O or X to validate, TRIANGLE to cancel", RGB(255, 255, 0));

							if (frame < 256) oslDrawFillRect(0, 0, 480, 272, RGBA(0, 0, 0, 255-frame));

							oslEndDrawing();
							oslSwapBuffers();
							oslWaitVSync();

							oslReadKeys();

							if ((osl_keys->pressed.up) && (ep > 0))
							{
								ep--;
							}
							if ((osl_keys->pressed.down) && (ep < 2))
							{
								ep++;
							}

							if (osl_keys->pressed.triangle)
							{
								j=2;
							}

							if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
							{
								j=1;
							}


							frame++;
						}

						ep=0;
						chl=ep*10+1;
					}

					if (chl == -1) j=2;
					if (j != 2) j=0;

					while ((!j) && (j != 2))
					{
						oslStartDrawing();
						oslSetFont(fonts[2]);
						oslSetTextColor(RGB(255, 255, 255));

							oslDrawFillRect(0, 0, 480, 272, RGB(22, 58, 68));

							oslDrawFillRect(120, 100, 360, 224, RGB(0, 0, 0));
							oslDrawFillRect(0, 16, 480, 48, RGB(11, 26, 34));

							oslDrawLine(360, 100, 360, 224, RGB(44, 116, 136));
							oslDrawLine(120, 224, 360, 224, RGB(44, 116, 136));
							oslDrawLine(120, 100, 120, 224, RGB(11, 26, 34));
							oslDrawLine(120, 100, 360, 100, RGB(11, 26, 34));

							spr_draw(choose_df, 120, 8);

							oslDrawFillRect(122, 108+chd*12, 358, 120+chd*12, RGBA(80, 80, 80,(int)(127+128*vfpu_sinf(0.05*frame+128))));


							for (k=0; k<4; k++)
							{
								center(108+k*12, diffs_names[k], RGB(255, 255, 255));
							}


						oslSetImageTileSize(pringle, chd*64, 0, 64, 64);
						spr_draw(pringle, 208, 158);

						oslSetFont(fonts[0]);
						center(258, "UP or DOWN to select difficulty, O or X to validate, TRIANGLE to cancel", RGB(255, 255, 0));

						oslEndDrawing();
						oslSwapBuffers();
						oslWaitVSync();

						oslReadKeys();

						if ((osl_keys->pressed.up) && (chd > 0))
						{
							chd--;
						}
						if ((osl_keys->pressed.down) && (chd < 3))
						{
							chd++;
						}

						if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
						{
							j=1;
							oslStopSound(theme);
							oslDeleteSound(theme);
						}

						if (osl_keys->pressed.triangle)
						{
							j=2;
						}

						frame++;

					}



					while (j != 2)
					{
						oslSetFont(fonts[0]);
						fadeout(RGB(0,0,0));
						if (chl != -1)
						{
							loadLevel(chl);

							if (chl != 10)
							{
								oslReadKeys();

								if (osl_keys->held.R)
								{
									sprintf(music_path, "./mzx/mzx1_0.mp3");
								}
								else
								{
									sprintf(music_path, "./mzx/mzx%d.xm", chl%10);
								}
							}
							else if (chl == 10)
							{
								sprintf(music_path, "./mzx/boss.xm");
							}

							sprite = (Sprite*) calloc(MAXSPRITES, sizeof(Sprite));

							j=game(options, startAngle, startPosX, startPosY, floor_color, ceiling_color, music_path, 0, sprite, chd+1);

							fadeout(RGB(0,0,0));

							free(sprite);
						}

						if (j != 3)
						{
							ammo=8;
							health=100;
							coins=0;
							weaponPossessed[2]=0;
							weaponPossessed[3]=0;
							weapon=1;
							armor=0;
						}
						else
						{
							if (chl%10)
							{
								chl++;
							}
							else if (chl==10)
							{
								theme = oslLoadSoundFileMOD("./mzx/theme.xm", OSL_FMT_NONE);
							    oslPlaySound(theme, 0);

								end_episode(ep);
								j=2;

								weapon=1;
								weaponPossessed[2]=0;
								weaponPossessed[3]=0;
								armor=0;
								health=100;
								ammo=8;
								coins=0;
							}
						}
					}

					if (oslGetSoundChannel(theme) != 0)
					{
						theme = oslLoadSoundFileMOD("./mzx/theme.xm", OSL_FMT_NONE);
						oslPlaySound(theme, 0);
					}
				break;

				case 1:
					oslStopSound(theme);

					if (worldMap[0][0] != -1) //Did you just launch a new game before choosing to edit a level? If no, we'll ask to keep the level already present in memory
					{
						oslStartDrawing();
						oslDrawFillRect(0, 0, 480, 272, RGB(0,0,0));
						oslDrawString(0, 262, "Keep the current map in memory? (O = YES, X = NO)");
						oslEndDrawing();
						oslSwapBuffers();
						i = oslWaitKey();
						if (i == OSL_KEY_CROSS)	level_editor(0); else if (i == OSL_KEY_CIRCLE) level_editor(1);
					}
					else //Start a new level if you just launched the game
					{
						level_editor(0);
					}

					oslPlaySound(theme, 0);
				break;

				case 2:
					chm=0;
					j=0;

					while (!j)
					{
						oslStartDrawing();
						oslDrawFillRect(0, 0, 480, 272, RGB(22, 58, 68));
						mainmenu(options[0], options[1], options[2], options[3], options[4], options[5], options[6], options[7], options[8], chm, hand);
						oslEndDrawing();
						oslSwapBuffers();

						oslReadKeys();

						if ((osl_keys->pressed.up) && (chm > 0))
						{
							chm--;
						}
						if ((osl_keys->pressed.down) && (chm < 8))
						{
							chm++;
						}

						if ((osl_keys->held.left))
						{
							switch(chm)
							{
								case 0:
								if (options[1] > 200)
								{
									options[1]--;
									if (options[3]) options[2]=(int)((float)(options[1]/1.76));
								}
								break;

								case 1:
								if (!options[3])
								{
									if (options[2] > 48) options[2]--;
								}
								break;
							}
						}

						if ((osl_keys->held.right))
						{
							switch(chm)
							{
								case 0:
								if (options[1] < 480)
								{
									options[1]++;
									if (options[3]) options[2]=(int)((float)(options[1]/1.76));
									if (options[2]>272) options[2]=272;
								}

								break;

								case 1:
								if (!options[3])
								{
									if (options[2] < 272) options[2]++;
								}
								break;
							}
						}

						if ((osl_keys->pressed.right) || (osl_keys->pressed.left) || (osl_keys->pressed.circle) || (osl_keys->pressed.cross))
						{
							switch(chm)
							{
								case 2:
								if (!options[3])
								{
									options[3]=1;
								}
								else options[3]=0;
								break;

								case 3:
								if (osl_keys->pressed.right)
								{
									options[0]++;
									if (options[0]==5) options[0]=1;
								}
								else if (osl_keys->pressed.left)
								{
									options[0]--;
									if (options[0]==0) options[0]=4;
								}
								break;

								case 4:
									if (!options[4]) options[4]=1; else options[4]=0;
								break;

								case 5:
									if (!options[5]) options[5]=1; else options[5]=0;
								break;

								case 6:
									/*if (osl_keys->pressed.right)
									{
										options[6]++;
										options[6]=options[6]%3;
									}
									else if (osl_keys->pressed.left)
									{
										options[6]--;
										if (options[6]) options[6]=2;
									}*/
								break;

								case 7:
									if (osl_keys->held.right)
									{
										if (options[8] < 100) options[8]+=4;
									}
									else if (osl_keys->held.left)
									{
										if (options[8] > 0) options[8]-=4;
									}

									oslPauseSound(theme, 1);
									theme -> volumeLeft = 163.84 * options[8];
								    theme -> volumeRight = 163.84 * options[8];
									oslPauseSound(theme, 0);
								break;

								case 8:
								if ((osl_keys->pressed.circle) || (osl_keys->pressed.cross))
								{
									j=1;
								}
								break;
							}
						}

					}

					chm=2;
				break;

				case 3:
					oslStopSound(theme);
					loadLevel(-2);
					sprite = (Sprite*) calloc(MAXSPRITES, sizeof(Sprite));
					game(options, startAngle, startPosX, startPosY, floor_color, ceiling_color, "./mzx/wolfen2.mp3", 1, sprite, chd); //The credits are just a tiny level
					free(sprite);
					oslPlaySound(theme, 0);
				break;

				case 4:
					quit=1;
				break;
			}

			fadeout(RGB(0,0,0));
			frame=0;

		}

    }

	oslDeleteImage(hand);
	oslDeleteImage(logo);
	oslDeleteSound(theme);

    oslDeinitAudio();
    oslEndGfx();

    oslQuit();

    return 0;
}






