//////////////////////////////////////////////////////////////////////////// /// Generic Turn-Based Battle Template /// Rev 0.2 - 7th Febryary, 2018 /// /// Requires Zelda Classic 2.54 /// By: ZoriaRPG /// /// ...Alpha 22 or later. /// For educational purposes. /// //////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////// /// Defines for game engine constants /// ///////////////////////////////////////// //General const int FFC_INVISIBLE_DATA = 0; //Screen->D const int SCREEN_D_BATTLES = 4; const int SCREEN_D_BATTLE_TIMER_CHANGED = 1; //Battles[] Array const int BATTLE_TIMER = 0; const int BATTLE_TIMER_MIN = 1; const int BATTLE_TIMER_MAX = 2; const int BATTLE_TIMER_DOBATTLE = 3; const int BATTLE_NUMNPCS = 4; const int BATTLE_MAX = 40; //NPC Misc / Attributes const int NPCM_ATTACKTIMER = 0; const int NPCA_INT = 0; const int NPCA_WIS = 1; const int NPCA_MORALE = 2; const int NPCA_SPEED = 3; const int NPCA_MP = 4; const int NPCA_SPELLS = 5; const int NPCA_INVENTORY = 6; const int NPCA_SPECIAL_STRING = 7; //Global Array Sizes const int GAS_NPCDATA = 512; const int GAS_MAPDATA = 512; const int GAS_ITEMDATA = 512; const int GAS_DROPDATA = 512; const int GAS_SHOPDATA = 512; const int GAS_NPCS = 256; const int GAS_ITEMS = 256; const int GAS_EWEAPONS = 256; const int GAS_LWEAPONS = 256; const int GAS_TEXTBUFFER = 1024; const int GAS_TYPEBUFFER = 129; const int GAS_GLOBALRAM = 4096; //Global arrays int Battles[BATTLE_MAX]; int Buffer[GAS_TEXTBUFFER]; int TypingBuffer[GAS_TYPEBUFFER]; int GameRAM[GAS_GLOBALRAM]; //Timers go here. npcdata NData[GAS_NPCDATA]; mapdata MapScr[GAS_MAPDATA]; itemdata IData[GAS_ITEMDATA]; dropsetdata DropData[GAS_DROPDATA]; shopdata ShopData[GAS_SHOPDATA]; ffc GlobalFF[MAX_FFCS]; //For on-screen sprited effects: npc GlobalNPC[GAS_NPCS]; item GlobalItem[GAS_ITEMS]; eweapon GlobalItem[GAS_EWEAPONS]; lweapon GlobalItem[GAS_LWEAPONS]; /////////////////////////////// /// Battle System Functions /// /////////////////////////////// //Disable battles, temporarily. void NoBattles() { } //Sets the minimum and maximum values of a timer. //These will be parsed as imputs for Rand(). void SetBattleTimerValues(int min, int max) { Battles[BATTLE_TIMER_MIN] = min; Battles[BATTLE_TIMER_MAX] = max; } //Sets the precise value of the ticking timer. void SetBattleTimerTick(int amt) { Battles[BATTLE_TIMER] = amt; } //Decrements the battle timer, and determines if there is a battle. //Call in the active script. void DecrementBattleTimer() { --Battles[BATTLE_TIMER]; if ( Battles[BATTLE_TIMER] <= 0 ) { Battles[BATTLE_TIMER] = 214748; Battles[BATTLE_TIMER_DOBATTLE] = 1; //this denotes tot he global script that we are runing a random encounter RandomEncounter(); } } //reset values when the battle ends void BattleOver(npcdata nd, int xp, int cold, int treasure) { bool awarded = AwardXP_Gold_Treasure(xp, gold, nd); SetBattleTimerTick( Rand(Battles[BATTLE_TIMER_MIN], Battles[BATTLE_TIMER_MAX]); } //award stuff after battles bool AwardXP_Gold_Treasure(int xp, int gold, npcdata special) { ffc f = Screen->LoadFFC(FFC_MENU_AWARDS); f->Data = FFC_INVISIBLE_DATA; f->Script = Game->GetFFCScript("BattleRewards"); f->InitD[3] = special; return true; } //This ffc displays Tango messages after a battle is over. ffc script BattleRewards { void run(int xp, int gold, npcdata special) { //Determine what items an npc drops dropsetdata dr = Game->LoadDropSetData(special->DropSet); //Do random drop chances based on dropsetdata. //Tango menus to display this stuff. } } //Place on a screen to have that screen change the battle timer for an area. ffc script FFC_Set_Battle_Timer_Values { void run(int min, int max, int reg, int bit, bool repeat) { if ( reg <= 0 ) { reg = SCREEN_D_BATTLES; } if ( bit <= 0 ) { bit = SCREEN_D_BATTLE_TIMER_CHANGED; } if ( !repeat ) { if ( !GetScreenDBit(reg, bit) ) { Battles[BATTLE_TIMER_MIN] = min; Battles[BATTLE_TIMER_MAX] = max; SetScreenDBit(reg, bit, true); } } else { Battles[BATTLE_TIMER_MIN] = min; Battles[BATTLE_TIMER_MAX] = max; } Quit(); } } //Runs a random encounter, based on the timer. void RandomEncounter() { mapdata m = Game->LoadMapDat(Game->GetCurMap(), Game->GetCurScreen()); npcdata e = Game->LoadNPCData(m-Enemy[Rand(10]l ffc f = Screen->LoadFFC(32); f->Script = Game->GetFFCScript("Battle"); f->InitD[0] = e; f->InitD[1] = m; //for drawing backdrops } //The battle menus run from here, as do all enemy actions. ffc script Battle { void run(npcdata e, mapdata m) { bool waiting; int mode; int action; while(1) { // Draw background using 'm' // draw npc using 'e' // determine e's attacks using it's attributes; // draw menus // determine who goes first mode = Rand(1); //if 1, enemy goes first while(mode) { //do enemy actions //Waitframe(); } while(!mode) { //player actions waiting = true; while(waiting) { //do_menus(); action = BattleMenu(); Waitframe(); } //resolve stuff this round Waitframe(); } } } // There are certainly other ways to handle these... // Vars used by the Tango menu. int menuCommand; int menuArg; //Tango Menu Init void SetUpWindow(int slot, int style, int x, int y, int size) { SetStyleSize(style, size); Tango_ClearSlot(slot); Tango_SetSlotStyle(slot, style); Tango_SetSlotPosition(slot, x, y); } //Quick way to drop a string into a Tango dialogue box. void ShowString(int string, int slot, int style, int x, int y) { SetUpWindow(slot, style, x, y, SIZE_LARGE); Tango_LoadString(slot, string); Tango_ActivateSlot(slot); while(Tango_SlotIsActive(slot)) Waitframe(); } //The Battle Menus called from the 'Battle' FFC. int BattleMenu() { int lineBreak[]="@26"; int line1[]="@choice(1)Attack@tab(40)@choice(2)Spell@26"; int line2[]="@choice(3)Item@tab(40)@choice(4)Item@domenu(1)@suspend()"; SetUpWindow(WINDOW_SLOT_1, WINDOW_STYLE_3, 32, 32, SIZE_LARGE); Tango_LoadString(WINDOW_SLOT_1, line1); Tango_AppendString(WINDOW_SLOT_1, line2); Tango_ActivateSlot(WINDOW_SLOT_1); while(!Tango_MenuIsActive()){ Waitframe(); } // Save the state again... int slotState[278]; int menuState[960]; int cursorPos; Tango_SaveSlotState(WINDOW_SLOT_1, slotState); Tango_SaveMenuState(menuState); int done = 0; int choice; while(true){ while( Tango_MenuIsActive() ) { cursorPos=Tango_GetMenuCursorPosition(); Waitframe(); } choice = Tango_GetLastMenuChoice(); if ( choice == 1 ) { // Item Info int text[256]; Game->GetMessage(msg,text); //Load msg into the buffer. ShowString(text, WINDOW_SLOT_2, WINDOW_STYLE_3, 48, 48); } else if ( choice == 2 ) { //Buy done = choice; menuArg = choice; } else if ( choice == 3 ) { //Cancel done = choice; } else if ( Link->PressEx1 ) { done = 1; } else done = 3; if ( done ) { break; // return choice; } else { Tango_RestoreSlotState(WINDOW_SLOT_1, slotState); Tango_RestoreMenuState(menuState); Tango_SetMenuCursorPosition(cursorPos); } } Tango_ClearSlot(WINDOW_SLOT_1); return done; }