Copy to Clipboard Test

Z3 Chest minigame EX Code

/////////////////////////////////

/// Z3 Style Chest Minigame   ///

/// v0.6 - 04-Jul-2022        ///

/// By: ZoriaRPG & Alucard648 ///

/////////////////////////////////

/// Final Release             ///

/////////////////////////////////



//Combos

const int CMB_CHEST_GAME_CLOSED = 948; //The 'closed' chest combo.

//! This should be combo type 'none', and solid.

const int CF_CHEST_GAME_PRIZE_DATA_MAIN_PRIZE = 10;



//Strings

const int STR_CHEST_GAME_OVER = 39; //Screen->Message string for the end of a game round.



//Sounds

const int SFX_OPEN_CHEST = 9; //The sound that will play when Link opens a chest, and an item is awarded.

const int SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE = 27; //The sound to play when the player finds the special item in a chest.

const int SFX_CHEST_GAME_START = 35; //The sound to play when the player starts the game.



//Other Settings and Options

const int CHEST_GAME_ALLOW_REPLAY = 0; //Set to '1' to allow the player to play again without leaving the screen.



const int FONT_CHEST_GAME = 0;//Font used to render various info in this minigame.

const int CSET_FONT_CHEST_GAME = 0x71;//Shadow for HUD font drawing (Color).

const int CHEST_GAME_COST_UI_X_OFFSET = 0;//Offsets for rendering cost per play between games.//NEW!!

const int CHEST_GAME_COST_UI_Y_OFFSET = -16;



//Game boy styled prize rendering

const int CHESTGAME_PRIZE_RENDER_TIMER = 30; //Time to render prize before acquisition, in frames.

const int CHESTGAME_PRIZE_RENDER_SPEED = 0.25; //Rising speed of revealed item during display.



const int CHESTGAME_PRIZE_HOLDUP = 1;//Item holdup animation on winning items. 0 - no hold up, 1 - main prize only, 2 - all items.



//Prompt GFX

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

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



//Lttp-style Treasure Chest minigame

//Pay up cost, then open 3 chests and clain found contents. Good luck!



//1.Set up 2 sequences of combos, 2 combos each:

// Chest - Closed, then open. Both combos must have "none" type and fully solid. Set CMB_CHEST_GAME_CLOSED to closed chest combo.

// Rupee then blank - for FFC itself to charge cost.

//2. --Prize table building--

// Set aside 1 unused screeen. Fill that screen with combos, whose ID`s (order in table, not combo type) are equal to ID`s of prize items, use the same combo multiple times to increase the chance of winning practicular item. 

// Flag "special item" combos (like heart piece ID) with CF_CHEST_GAME_PRIZE_DATA_MAIN_PRIZE flag, so upon winning this item, Screen`s Special Item flag will set on and any furtner such win cases will reward backup item. Use screen`s undercombo (the screen, where the game is located) to define backup prize ID.

//--

//3.Place chests in the game screen, using only CMB_CHEST_GAME_CLOSED combos.

//4.Place FFC with Rupee combo at location, where Link could pay up cost to start minigame.

// D0 - number of chests to open per game

// D1 - Map for locating prize table. (step 2)

// D2 - Screen used to define prize table. (step 2)

// D3 - 1 - turn the game into classic Money making game - Combo ID`s define amout of rupees to gain/lose. CF_CHEST_GAME_PRIZE_DATA_MAIN_PRIZE sets negative number.

// D4 - Cost per play... //NEW!!

//     #####.____ - counter amount to pay.

//     _____.#### - ID of counter used to pay. (rupees by default, NOT HP!!)

// D5 #####.____ - String to display as intro when entering the screen with game.

// D5 _____.#### - String to display on game start. //NEW!!

// D6 - String to display when the game is over

// D7 - 1 - allow replaying the game without exiting/reentring screen.





ffc script LTTPItemChestMiniGame{	

	void run(int max_chests_Link_can_open, int prizedatamap, int prizedatascreen, int moneygame, int costPerPlay, int msgRules, int msgEnd, int allowReplay){		

		int ChestPrizes[176];

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

			ChestPrizes[i]=Game->GetComboData(prizedatamap, prizedatascreen, i);

			if (Game->GetComboFlag(prizedatamap, prizedatascreen, i)==CF_CHEST_GAME_PRIZE_DATA_MAIN_PRIZE) ChestPrizes[i]*=-1;

		}

		int initialData = this->Data; //Store the initial combo, to revert, if replay is enabled. 

		int check=-1;

		int cmb=-1;

		int adjcmb =-1;

		int has_opened_number_of_chests=0;

		bool gameRunning = false;

		bool gameOver = false;

		bool giveprize = false;		

		item it;

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

		

		int msgInit	 =  GetHighFloat(msgRules);

		int msgStart = GetLowFloat(msgRules);

		

		int CostCounter =  GetLowFloat(costPerPlay);

		int CostPlay = GetHighFloat(costPerPlay);

		if (CostCounter==0) CostCounter=1;

		

		if ( msgInit >0) Screen->Message(msgRules);//Show the string for the chest game rules. 

		

		while(true) {

			if ( max_chests_Link_can_open == has_opened_number_of_chests ) gameOver = true;		

			if ( gameOver && ( CHEST_GAME_ALLOW_REPLAY || allowReplay > 0 ) ) {

				gameOver = false;

				gameRunning = false;

				this->Data = initialData;

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

					if ( Screen->ComboD[q] == CMB_CHEST_GAME_CLOSED+1 ) Screen->ComboD[q] = CMB_CHEST_GAME_CLOSED;

				}

				has_opened_number_of_chests = 0;

			}

			if (!gameRunning){

				if (CSET_FONT_CHEST_GAME>0)Screen->DrawInteger(2, this->X+1+CHEST_GAME_COST_UI_X_OFFSET, this->Y+1+CHEST_GAME_COST_UI_Y_OFFSET, FONT_CHEST_GAME,CSET_FONT_CHEST_GAME,-1, -1, -1, -CostPlay, 0, OP_OPAQUE);

				Screen->DrawInteger(2, this->X+CHEST_GAME_COST_UI_X_OFFSET, this->Y+CHEST_GAME_COST_UI_Y_OFFSET, FONT_CHEST_GAME,1,-1, -1, -1, -CostPlay, 0, OP_OPAQUE);

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

			}

			if (origcmb==cmb && Game->Counter[CostCounter] >= CostPlay && !gameRunning ) {

				Screen->FastCombo(6, Link->X,Link->Y-15,CMB_CHESTGAME_PROMPT, CSET_CHESTGAME_PROMPT,OP_OPAQUE);

				if (Link->PressA||Link->PressB||Link->PressEx1){

					//If Link collides with the ffc, which should show the cost, and presses a button, start the game. 

					if ( SFX_CHEST_GAME_START ) Game->PlaySound(SFX_CHEST_GAME_START);

					if ( msgStart >0) Screen->Message(msgStart);

					gameRunning = true;

					Game->DCounter[CostCounter] -= CostPlay;

					this->Data++; //increase to the next combo, removing the cost icon.

				}

			}			

			if (gameRunning) {				

				//Check to see if Link can open chest				

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

				adjcmb = LttpChestAdjacentComboFix(cmb, Link->Dir);

				if (Screen->ComboD[adjcmb]==CMB_CHEST_GAME_CLOSED&&Link->Dir==DIR_UP){

					Screen->FastCombo(6, Link->X,Link->Y-15,CMB_CHESTGAME_PROMPT, CSET_CHESTGAME_PROMPT,OP_OPAQUE);

					if (Link->PressA||Link->PressB||Link->PressEx1){

						has_opened_number_of_chests++; 

						Game->PlaySound(SFX_OPEN_CHEST);

						Screen->ComboD[adjcmb]++;

						giveprize=true;

					}

				}

				if (giveprize) {

					if (moneygame>0){

						check = Rand(176);

						check = ChestPrizes[check];

						Game->DCounter[CostCounter]+= check;

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

							if (CSET_FONT_CHEST_GAME>0) Screen->DrawInteger(1, ComboX(adjcmb)-Cond((check<0||check>100), 4,0)+1, ComboY(adjcmb)+1, FONT_CHEST_GAME,CSET_FONT_CHEST_GAME,-1, -1, -1, check, 0, OP_OPAQUE);

							Screen->DrawInteger(1, ComboX(adjcmb)-Cond((check<0||check>100), 4,0), ComboY(adjcmb), FONT_CHEST_GAME,1,-1, -1, -1, check, 0, OP_OPAQUE);

							Waitframe();

						}

					}

					else{

						check = Rand(176);

						//Trace(check);

						int itemID = Abs(ChestPrizes[check]);

						if (ChestPrizes[check]<0 && Screen->State[ST_SPECIALITEM]) itemID = Screen->UnderCombo;

						if (CHESTGAME_PRIZE_RENDER_TIMER>0){

							item Temp = CreateItemAt(itemID, 0, 0);

							int itemtile = Temp->OriginalTile;

							int itemcset = Temp->CSet;

							int itemRaise = 0;

							Remove(Temp);

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

								Screen->FastTile(1, ComboX(adjcmb), ComboY(adjcmb)-itemRaise, itemtile, itemcset, OP_OPAQUE);

								itemRaise+=CHESTGAME_PRIZE_RENDER_SPEED;

								NoAction();

								Waitframe();

							}

						}

						it = CreateItemAt(itemID, Link->X, Link->Y);

						if (ChestPrizes[check]<0 && !Screen->State[ST_SPECIALITEM]){

							if (CHESTGAME_PRIZE_HOLDUP>0)it->Pickup +=IP_HOLDUP;

							it->Pickup |= IP_ST_SPECIALITEM;

							Game->PlaySound(SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE);

						}

						if (CHESTGAME_PRIZE_HOLDUP==2)it->Pickup +=IP_HOLDUP;

					}

					giveprize=false;

				}

				

				if ( has_opened_number_of_chests >= max_chests_Link_can_open ) {

					gameOver = true;

					gameRunning = false;

					if ( msgEnd ) Screen->Message(msgEnd);

					else Screen->Message(STR_CHEST_GAME_OVER);

					if (!CHEST_GAME_ALLOW_REPLAY && !allowReplay )Quit();

				}

			}		

			Waitframe();

		}

	}	

}



//Fixed variant of AdjacentCombo function from std_extension.zh

int LttpChestAdjacentComboFix(int cmb, int dir)

{

	int combooffsets[13]={-0x10, 0x10, -1, 1, -0x11, -0x0F, 0x0F, 0x11};

	if ( cmb % 16 == 0 ) combooffsets[9] = -1;//if it's the left edge

	if ( (cmb % 16) == 15 ) combooffsets[10] = -1; //if it's the right edge

	if ( cmb < 0x10 ) combooffsets[11] = -1; //if it's the top row

	if ( cmb > 0x9F ) combooffsets[12] = -1; //if it's on the bottom row

	if ( combooffsets[9]==-1 && ( dir == DIR_LEFT || dir == DIR_LEFTUP || dir == DIR_LEFTDOWN ) ) return -1; //if the left columb

	if ( combooffsets[10]==-1 && ( dir == DIR_RIGHT || dir == DIR_RIGHTUP || dir == DIR_RIGHTDOWN ) ) return -1; //if the right column

	if ( combooffsets[11]==-1 && ( dir == DIR_UP || dir == DIR_RIGHTUP || dir == DIR_LEFTUP ) ) return -1; //if the top row

	if ( combooffsets[12]==-1 && ( dir == DIR_DOWN || dir == DIR_RIGHTDOWN || dir == DIR_LEFTDOWN ) ) return -1; //if the bottom row

	if ( cmb >= 0 && cmb < 176 ) return cmb + combooffsets[dir];

	else return -1;

}