/////////////////////////////////
/// 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;
}