Copy to Clipboard Test

Metroidvania Warp Network System Code

const int CT_MV_WARP = 142;//Combo type for MetroidVania warp portals. Script 1 by default



const int MIDI_MW_WARP_TELEPORT = 6;//MIDI that plays during teleportation Must be a non-looping one.



const int MW_WARP_TELEPORT_DURATION = 240;//Duration of teleporting animation



const int FONT_MW_WARP_UI = 0;//Font used to render in-game instruction manual for warp portals.

const int COLOR_MV_WARP_UI_FONT_SHADOW = 16;//Color of shadow to render for UI strings.

const int FONT_MV_WARP_TEXT_X_OFFSET = 0;//UI text X offset, in pixels. NEW!! 



const int TILE_MW_WARP_FRAME = 20052;//Top left corner of 3x3 frame used to render around the screen when user chooses warp destination

const int CSET_MW_WARP_FRAME = 7;//CSet used to render frame around the screen when user chooses warp destination



const int CMB_MW_WARP_TELEPORT_CLOUD = 912;//Combo ID used to render full-screen teleport animation.

const int CSET_MW_WARP_TELEPORT_CLOUD = 5;//CSet used to render full-screen teleport animation.



const int CMB_MW_WARP_PROMPT = 911;//Combo ID used to render prompt, when Link steps on warp spot.

const int CSET_MW_WARP_PROMPT = 11;//CSet used to render prompt, when Link steps on warp spot.



const int SFX_MV_WARP_RECORD = 7;//Sound that plays when a new warp spot is recorded into portal network system.



const int COLOR_MW_WARP_IMAGE_SHADOW = 1;//Color used to render shadow of preview image in warping UI.

const int MW_WARP_IMAGE_TILE_WIDTH = 4;//Tile width and tile height used to render preview images for warps.

const int MW_WARP_IMAGE_TILE_HEIGHT = 3;



int MV_WARP_DMAP[512];//Global arrays. 7 arrays used.

int MV_WARP_SCREEN[512];

int MV_WARP_LEVEL[512];

int MV_WARP_MAP[512];

int MV_WARP_MAPSCR[512];

int MV_WARP_PREVIEW_TILE[512];

int MV_WARP_PREVIEW_CSET[512];





//Metroidvania Warp Network System

//A set of portals, usually scattered across entire quest, that allows Link to warp between previously visited places for fast travel.

//Visit 2 or more screens with those warp spots, stand on warp spot FFC, press A to open menu with all available destinations. Cycle between warp spots with Left/Right then press A to confirm teleportation.



//Uses up 7 global arrays.

//1. Set up 3x3 frame for warp menu.

//2. Set up 2 combos, 1 for prompt combo (a speech bubble that appears above Link, when he steps on warp spot) and 1 for full screen teleportation animation.

//3. Check out constants inside the script file, especially CMB_MW_WARP_TELEPORT_CLOUD, CMB_MW_WARP_PROMPT and CMB_MW_WARP_PROMPT.

//4. Import and compile the script. Assign FFC script.

//5. Construct warp screens using only palette-independant CSets. That`s because Screen->DrawScreen uses current palette for rendering warp position selecting and there is no way to change that.

//6. Place warp spot - A combo with CT_MV_WARP combo type, warp return point A (or legacy warp arrival square, if used) and FFC with script onto the same position. 

// D0 - Id of top left tile for screen screen preview image. 

// D1 - CSet used for drawing that image.

//7. Repeat step 6 for each warp point in the quest.



global script Init{

	void run(){

		InitMetroidvaniaWarpData();

	}

}



void InitMetroidvaniaWarpData(){

	for (int i=0;i<512;i++){

		MV_WARP_DMAP[i]=-1;

		MV_WARP_SCREEN[i]=-1;

		MV_WARP_LEVEL[i]=-1;

		MV_WARP_MAP[i]=-1;

		MV_WARP_MAPSCR[i]=-1;

		MV_WARP_PREVIEW_TILE[i]=-1;

		MV_WARP_PREVIEW_CSET[i]=-1;

	}

}



ffc script MetroidvaniaWarpSpot{

	void run( int tile, int cset){

		if (tile==0) tile=-1;

		int origcmb = ComboAt(CenterX(this), CenterY(this));

		while(Screen->ComboT[origcmb]!=CT_MV_WARP) Waitframe();

		if (WarpHasRecoeded()<0)RecordWarpPoint(tile,cset);

		int cmb=-1;

		int state = 0;

		int curid=-1;

		int teletimer = MW_WARP_TELEPORT_DURATION;

		

		int str1[] = "Select Warp Destination";

		int str2[] = "Left/Right - Cycle";

		int str3[] = "A - Confirm, B - Cancel";

		

		while(true){

			if (state==0){

				cmb = ComboAt(CenterLinkX(), CenterLinkY());

				if (cmb==origcmb){

					Screen->FastCombo(6, Link->X,Link->Y-15,CMB_MW_WARP_PROMPT, CSET_MW_WARP_PROMPT,OP_OPAQUE);

					if (Link->PressA){

						curid = WarpHasRecoeded();

						state=1;

					}

				}

			}

			else if (state==1){

				if (Link->PressRight){

					curid++;

					if (curid>=512)curid=0;

					while(MV_WARP_DMAP[curid]<0){

						curid++;

						if (curid>=512)curid=0;

					}

				}

				if (Link->PressLeft){

					curid--;

					if (curid<0)curid=511;

					while(MV_WARP_DMAP[curid]<0){

						curid--;

						if (curid<0)curid=511;

					}

				}

				if (Link->PressB){

					state=0;

				}

				if (Link->PressA){

					Game->PlayMIDI(MIDI_MW_WARP_TELEPORT);

					state=2;

				}

				Screen->Rectangle(6, 0, 0, 256, 176, 0, 1, 1, 1, 0, true, OP_OPAQUE);

				if (MV_WARP_PREVIEW_TILE[curid]>=0){

					if (COLOR_MW_WARP_IMAGE_SHADOW>0)Screen->Rectangle(6, 130-MW_WARP_IMAGE_TILE_WIDTH*8, 74, 130+MW_WARP_IMAGE_TILE_WIDTH*8, 74+MW_WARP_IMAGE_TILE_HEIGHT*16, COLOR_MW_WARP_IMAGE_SHADOW, 1, 1, 1, 0, true, OP_OPAQUE);

					Screen->DrawTile	(6, 128-MW_WARP_IMAGE_TILE_WIDTH*8, 72, MV_WARP_PREVIEW_TILE[curid], MW_WARP_IMAGE_TILE_WIDTH, MW_WARP_IMAGE_TILE_HEIGHT, MV_WARP_PREVIEW_CSET[curid], -1, -1,0 ,0 , 0, 0, false, OP_OPAQUE);

				}

				else Screen->DrawScreen(6,MV_WARP_MAP[curid], MV_WARP_MAPSCR[curid],0,0,0);

				DrawFrame(6,TILE_MW_WARP_FRAME,0,0,16,10,CSET_MW_WARP_FRAME,OP_OPAQUE);

				if (COLOR_MV_WARP_UI_FONT_SHADOW>0){

					Screen->DrawString(6, 33+FONT_MV_WARP_TEXT_X_OFFSET, 17, FONT_MW_WARP_UI, COLOR_MV_WARP_UI_FONT_SHADOW, -1, 0, str1, OP_OPAQUE);

					Screen->DrawString(6, 33+FONT_MV_WARP_TEXT_X_OFFSET, 25, FONT_MW_WARP_UI, COLOR_MV_WARP_UI_FONT_SHADOW, -1, 0, str2, OP_OPAQUE);

					Screen->DrawString(6, 33+FONT_MV_WARP_TEXT_X_OFFSET, 33, FONT_MW_WARP_UI, COLOR_MV_WARP_UI_FONT_SHADOW, -1, 0, str3, OP_OPAQUE);

				}

				Screen->DrawString(6, 32+FONT_MV_WARP_TEXT_X_OFFSET, 16, FONT_MW_WARP_UI, 1, -1, 0, str1, OP_OPAQUE);

				Screen->DrawString(6, 32+FONT_MV_WARP_TEXT_X_OFFSET, 24, FONT_MW_WARP_UI, 1, -1, 0, str2, OP_OPAQUE);

				Screen->DrawString(6, 32+FONT_MV_WARP_TEXT_X_OFFSET, 32, FONT_MW_WARP_UI, 1, -1, 0, str3, OP_OPAQUE);

				NoAction();

			}

			else if (state==2){

				teletimer--;

				for (int i=0; i<176;i++){

					Screen->FastCombo(6, ComboX(i),ComboY(i),CMB_MW_WARP_TELEPORT_CLOUD, CSET_MW_WARP_TELEPORT_CLOUD,OP_OPAQUE);

				}

				if (teletimer<=0){

					Screen->Rectangle(6, 0, 0, 256, 176, 1, 1, 1, 1, 0, true, OP_OPAQUE);

					Waitframe();

					Link->Warp(MV_WARP_DMAP[curid],MV_WARP_SCREEN[curid]);

					Quit();

				}

				NoAction();

			}

			Waitframe();

		}

	}

}



int WarpHasRecoeded(){

	int dmap = Game->GetCurDMap();

	int scrn = Game->GetCurDMapScreen();

	int lvl = Game->GetCurLevel();

	for (int i=0;i<512;i++){

		if (MV_WARP_DMAP[i]!=dmap)continue;

		if (MV_WARP_SCREEN[i]!=scrn)continue;

		if (MV_WARP_LEVEL[i]!=lvl)continue;

		return i;

	}

	return -1;

}



void RecordWarpPoint(int tile, int cset){

	Game->PlaySound(SFX_MV_WARP_RECORD);

	for (int i=0;i<512;i++){

		if (MV_WARP_DMAP[i]>=0)continue;

		MV_WARP_DMAP[i] = Game->GetCurDMap();

		MV_WARP_SCREEN[i] = Game->GetCurDMapScreen();

		MV_WARP_LEVEL[i]= Game->GetCurLevel();

		MV_WARP_MAP[i]=Game->GetCurMap();

		MV_WARP_MAPSCR[i]=Game->GetCurScreen();

		MV_WARP_PREVIEW_TILE[i] = tile;

		MV_WARP_PREVIEW_CSET[i] = cset;

		return;

	}

}



void DrawFrame(int layer, int tile, int posx, int posy, int sizex, int sizey, int CSet, int opacity){

	int drawx = posx;

	int drawy = posy;

	int xoffset=0;

	int yoffset=0;

	for (int w=0; w<sizex; w++){

		drawx = posx+16*w;

		xoffset=0;

		if (w>0)xoffset=1;

		if (w==sizex-1) xoffset=2;

		for (int h=0; h<sizey; h++){

			drawy = posy+16*h;

			yoffset=0;

			if (h>0)yoffset=1;

			if (h==sizey-1) yoffset=2;

			Screen->FastTile(layer, drawx, drawy, tile +xoffset+20*yoffset, CSet, opacity);

		}

	}

}