Advertisement
HylianWhovian

FairyQstScript12_31_2019

Dec 30th, 2019
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 176.97 KB | None | 0 0
  1. #option BINARY_32BIT off
  2. //Would break a number of things if set on
  3. #option SHORT_CIRCUIT on
  4. //Should work for everything in std_zh, and just speed it up
  5.  
  6. import "std.zh"
  7.  
  8.  
  9. //Main Files
  10. #include "std_zh/std_constants.zh"
  11. #include "std_zh/std_functions.zh"
  12. #include "std_zh/std_vars.zh" //Basic array, and some generic handlers. Useful in preventing quest fixing/expansion issues.
  13.  
  14. //ZScript string handling functions, akin to those found in C
  15. //#include "string.zh"
  16. #include "std_zh/string_constants.zh" //Now #includeed from here. This prevents conflicts for those people
  17. #include "std_zh/string_functions.zh" //who would #include string.zh from a secondary source, as that file is now
  18. //empty, and the string.ch components load from here.
  19.  
  20. //New Functions, for 2.53.0 and above
  21. #include "std_zh/std_extension.zh"
  22.  
  23. //Keyboard handling for 2.54 and above
  24. #include "std_zh/std_keyboard.zh"
  25.  
  26. //Locale
  27. #include "std_zh/locale/std_EnglishIntl.zh" //International English Localisation
  28.  
  29. //Settings
  30. #include "std_zh/std.cfg"
  31.  
  32. // ffcscript.zh
  33. // Version 1.1.1
  34.  
  35. // Combo to be used for generic script vehicle FFCs. This should be
  36. // an invisible combo with no type or flag. It cannot be combo 0.
  37. const int FFCS_INVISIBLE_COMBO = 1;
  38.  
  39. // Range of FFCs to use. Numbers must be between 1 and 32.
  40. const int FFCS_MIN_FFC = 1;
  41. const int FFCS_MAX_FFC = 32;
  42.  
  43.  
  44. int RunFFCScript(int scriptNum, float args)
  45. {
  46. // Invalid script
  47. if(scriptNum<0 || scriptNum>511)
  48. return 0;
  49.  
  50. ffc theFFC;
  51.  
  52. // Find an FFC not already in use
  53. for(int i=FFCS_MIN_FFC; i<=FFCS_MAX_FFC; i++)
  54. {
  55. theFFC=Screen->LoadFFC(i);
  56.  
  57. if(theFFC->Script!=0 ||
  58. (theFFC->Data!=0 && theFFC->Data!=FFCS_INVISIBLE_COMBO) ||
  59. theFFC->Flags[FFCF_CHANGER])
  60. continue;
  61.  
  62. // Found an unused one; set it up
  63. theFFC->Data=FFCS_INVISIBLE_COMBO;
  64. theFFC->Script=scriptNum;
  65.  
  66. if(args!=NULL)
  67. {
  68. for(int j=Min(SizeOfArray(args), 8)-1; j>=0; j--)
  69. theFFC->InitD[j]=args[j];
  70. }
  71.  
  72. return i;
  73. }
  74.  
  75. // No FFCs available
  76. return 0;
  77. }
  78.  
  79. ffc RunFFCScriptOrQuit(int scriptNum, float args)
  80. {
  81. // Invalid script
  82. if(scriptNum<0 || scriptNum>511)
  83. Quit();
  84.  
  85. int ffcID=RunFFCScript(scriptNum, args);
  86. if(ffcID==0)
  87. Quit();
  88.  
  89. return Screen->LoadFFC(ffcID);
  90. }
  91.  
  92. int FindFFCRunning(int scriptNum)
  93. {
  94. // Invalid script
  95. if(scriptNum<0 || scriptNum>511)
  96. return 0;
  97.  
  98. ffc f;
  99.  
  100. for(int i=1; i<=32; i++)
  101. {
  102. f=Screen->LoadFFC(i);
  103. if(f->Script==scriptNum)
  104. return i;
  105. }
  106.  
  107. // No FFCs running it
  108. return 0;
  109. }
  110.  
  111. int FindNthFFCRunning(int scriptNum, int n)
  112. {
  113. // Invalid script
  114. if(scriptNum<0 || scriptNum>511)
  115. return 0;
  116.  
  117. ffc f;
  118.  
  119. for(int i=1; i<=32; i++)
  120. {
  121. f=Screen->LoadFFC(i);
  122. if(f->Script==scriptNum)
  123. {
  124. n--;
  125. if(n==0)
  126. return i;
  127. }
  128. }
  129.  
  130. // Not that many FFCs running it
  131. return 0;
  132. }
  133.  
  134. int CountFFCsRunning(int scriptNum)
  135. {
  136. // Invalid script
  137. if(scriptNum<0 || scriptNum>511)
  138. return 0;
  139.  
  140. ffc f;
  141. int numFFCs=0;
  142.  
  143. for(int i=1; i<=32; i++)
  144. {
  145. f=Screen->LoadFFC(i);
  146. if(f->Script==scriptNum)
  147. numFFCs++;
  148. }
  149.  
  150. return numFFCs;
  151. }
  152.  
  153. //=============================================================================
  154. // stdExtra.zh version 3.5
  155. // Latest update:
  156. // * Added SCREEN_COMBOS
  157. // * Removed equipItemA/B()
  158. // * Removed SelectPressInput() and SetInput
  159. // * Added RadianVectorX/Y by Mero
  160. // * Removed cw() and ccw() and added rotateDir() by Mero
  161. //=============================================================================
  162.  
  163. //Pre-requisites
  164. //#include "std.zh"
  165. //#include "ffcscript.zh"
  166. //#include "string.zh"
  167.  
  168. //==== * Quest-Specific Settings * ============================================
  169.  
  170. //Text colors
  171. const int COLOR_WHITE = 0x01;
  172. const int COLOR_BLACK = 0x0F;
  173.  
  174. //Combos
  175. const int CMB_BLANK = 0; //Leave this be - combo 0 should always be invisible and no properties
  176. const int CMB_FREEZEALL = 892; //Combo with "Freeze all (Except FFCs)" type
  177. const int CMB_FREEZEFFC = 893; //Combo with "Freeze all (FFCs only)" type
  178.  
  179. //FFC Slots
  180. const int FFC_FREEZEALL = 31;
  181. const int FFC_FREEZEFFC = 32;
  182.  
  183. //Other Settings
  184. const int MAX_ITEMS = 255; //Set to the highest item ID you use to make GetCurrentItem() more efficient
  185.  
  186. //=============================================================================
  187.  
  188. //Screen Dimensions
  189. const int SCREEN_WIDTH = 256;
  190. const int SCREEN_HEIGHT = 176;
  191. const int SCREEN_VISIBLEHEIGHT = 168; //The height of the screen you can see (bottom 8 pixels cut off)
  192. const int SCREEN_SSTOP = -64; //The top of the subscreen
  193. const int SCREEN_COMBOS = 176; // Number of combos on screen
  194.  
  195. //Sprite Flips and rotations
  196. const int FLIP_NO = 0; //Not flipped
  197. const int FLIP_H = 1; //Horizontal
  198. const int FLIP_V = 2; //Vertical
  199. const int FLIP_B = 3; //Vertical & Horizontal
  200. const int ROTATE_CW = 4; //Clockwise
  201. const int ROTATE_CCW = 7; //Counter-clockwise
  202. const int ROTATE_CW_FLIP = 5;
  203. const int ROTATE_CCW_FLIP = 6;
  204.  
  205. //NPC Misc Flags
  206. const int NPCMF_DAMAGE = 0x0001; //"Damaged by Power 0 weapons"
  207. const int NPCMF_INVISIBLE = 0x0002; //"Is invisible"
  208. const int NPCMF_NOTRETURN = 0x0004; //"Never returns after death"
  209. const int NPCMF_NOTENEMY = 0x0008; //"Doesn't count as beatable enemy"
  210. //const int NPCMF_SPAWNFLICKER = 0x0010; //Spawn animation = flicker (???)
  211. const int NPCMF_LENSONLY = 0x0020; //"Can only be seen with Lens of Truth"
  212. //const int NPCMF_FLASHING = 0x0040;
  213. //const int NPCMF_FLICKERING = 0x0080;
  214. //const int NPCMF_TRANSLUCENT = 0x0100;
  215. const int NPCMF_SHIELDFRONT = 0x0200;
  216. const int NPCMF_SHIELDLEFT = 0x0400;
  217. const int NPCMF_SHIELDRIGHT = 0x0800;
  218. const int NPCMF_SHIELDBACK = 0x1000;
  219. const int NPCMF_HAMMERBREAK = 0x2000; //"Hammer can break shield"
  220.  
  221. //===============================================================================
  222. //Reusable scripts
  223. //===============================================================================
  224.  
  225. //Run an FFC script
  226. //D0-D6: Arguments for the FFC Script
  227. //D7: The script number to run
  228. item script ffcItem{
  229. void run(int d0, int d1, int d2, int d3, int d4, int d5, int d6, int ffc_id){
  230. int d[7] = {d0,d1,d2,d3,d4,d5,d6};
  231. if(FindFFCRunning(ffc_id)<=0){
  232. RunFFCScriptOrQuit(ffc_id, d);
  233. }
  234. }
  235. }
  236.  
  237. //===============================================================================
  238. //Position and movement
  239. //===============================================================================
  240.  
  241. //Prevents moving in any direction
  242. void NoMovement(){
  243. Link->InputUp = false; Link->PressUp = false;
  244. Link->InputDown = false; Link->PressDown = false;
  245. Link->InputLeft = false; Link->PressLeft = false;
  246. Link->InputRight = false; Link->PressRight = false;
  247. }
  248.  
  249. //Converts velocity into a direction.
  250. int VelocityToDir(float x, float y){
  251. if(x == 0 && y == 0) return -1;
  252. return RadianAngleDir8(RadianAngle(0, x, 0, y));
  253. }
  254.  
  255. int VelocityToDir4(float x, float y){
  256. if(x == 0 && y == 0) return -1;
  257. return RadianAngleDir4(RadianAngle(0, x, 0, y));
  258. }
  259.  
  260. //Converts the x component of a velocity into a direction.
  261. int XSpeedToDir(float x){
  262. return VelocityToDir(x, 0);
  263. }
  264.  
  265. //Converts the y component of a velocity into a direction.
  266. int YSpeedToDir(float y){
  267. return VelocityToDir(0, y);
  268. }
  269.  
  270. //Takes a direction of movement and gets the xspeed.
  271. float DirToXSpeed(int dir){
  272. if(dir<4)
  273. return Cond((dir*2)-5 < -1, 0, (dir*2)-5);
  274. else
  275. return Cond(dir<6, -1.5, 1.5);
  276. }
  277.  
  278. //Takes a direction of movement and gets the yspeed.
  279. float DirToYSpeed(int dir){
  280. if(dir > 7) dir = toggleBlock(dir);
  281. if(dir < 2) return 0;
  282. float ret = 1;
  283. if(dir >= 4) ret += .5;
  284. return Cond(IsEven(dir), -ret, ret);
  285. }
  286.  
  287. //Returns the angle in radians of a direction; used for weapon angles
  288. float dirToRad(int dir){
  289. if ( dir == DIR_UP )
  290. return 1.5 * PI;
  291. if ( dir == DIR_DOWN )
  292. return .5 * PI;
  293. if ( dir == DIR_LEFT )
  294. return PI;
  295. if ( dir == DIR_RIGHT )
  296. return 0;
  297. }
  298.  
  299. int dirToDeg(int dir){
  300. if ( dir == DIR_UP )
  301. return 90;
  302. if ( dir == DIR_DOWN )
  303. return 270;
  304. if ( dir == DIR_LEFT )
  305. return 180;
  306. if ( dir == DIR_RIGHT )
  307. return 0;
  308. }
  309.  
  310. // Returns value from 0 to 360 rather than -180 to 180
  311. float AnglePos(int x1, int y1, int x2, int y2){
  312. float angle = ArcTan(x2-x1, y2-y1)*57.2958;
  313. if(angle < 0)
  314. angle += 360;
  315. return angle;
  316. }
  317.  
  318. // Returns the X component of a radian angle.
  319. float RadianVectorX(float len, float angle)
  320. {
  321. return len * RadianCos(angle);
  322. }
  323.  
  324. // Returns the Y component of a radian angle.
  325. float RadianVectorY(float len, float angle)
  326. {
  327. return len * RadianSin(angle);
  328. }
  329.  
  330. //Returns the distance between the given Coordinate and Link's Center.
  331. float DistanceLink(float x, float y)
  332. {
  333. return Distance(CenterLinkX(), CenterLinkY(), x, y);
  334. }
  335.  
  336. //Returns the distance between Link's center and an object's center.
  337. float DistanceLink(ffc f)
  338. {
  339. return Distance(CenterLinkX(), CenterLinkY(), CenterX(f), CenterY(f));
  340. }
  341. float DistanceLink(npc n)
  342. {
  343. return Distance(CenterLinkX(), CenterLinkY(), CenterX(n), CenterY(n));
  344. }
  345. float DistanceLink(lweapon l)
  346. {
  347. return Distance(CenterLinkX(), CenterLinkY(), CenterX(l), CenterY(l));
  348. }
  349. float DistanceLink(eweapon e)
  350. {
  351. return Distance(CenterLinkX(), CenterLinkY(), CenterX(e), CenterY(e));
  352. }
  353.  
  354. //Converts 8-way direction to 4-way
  355. int dir8ToDir4(int dir)
  356. {
  357. if(dir != Clamp(dir, 0, 15)) return -1;
  358. dir &= 7;
  359. if((dir & 4) == 0)
  360. return dir;
  361. else
  362. return Cond(IsEven(dir), DIR_UP, DIR_DOWN);
  363. }
  364.  
  365. //Returns the reverse of the given direction.
  366. int reverseDir(int dir)
  367. {
  368. if(dir != Clamp(dir, 0, 15)) return -1; //Invalid direction
  369. return Cond(dir<8, OppositeDir(dir), ((dir+4)%8)+8);
  370. }
  371.  
  372. // Rotates a given direction
  373. int rotateDir(int dir, bool ccw, bool eightway)
  374. {
  375. if(dir==DIR_UP) dir = 0;
  376. else if(dir==DIR_RIGHTUP) dir = 1;
  377. else if(dir==DIR_RIGHT) dir = 2;
  378. else if(dir==DIR_RIGHTDOWN) dir = 3;
  379. else if(dir==DIR_DOWN) dir = 4;
  380. else if(dir==DIR_LEFTDOWN) dir = 5;
  381. else if(dir==DIR_LEFT) dir = 6;
  382. else if(dir==DIR_LEFTUP) dir = 7;
  383. else return -1; //Invalid Direction;
  384.  
  385. if(eightway)
  386. dir=(dir+Cond(ccw, 7,1))%8;
  387. else
  388. dir=(dir+Cond(ccw,6,2))%8; //Will never be odd. And needs to wrap by 8 regardless.
  389.  
  390. if(dir==0) return DIR_UP;
  391. else if(dir==1) return DIR_RIGHTUP;
  392. else if(dir==2) return DIR_RIGHT;
  393. else if(dir==3) return DIR_RIGHTDOWN;
  394. else if(dir==4) return DIR_DOWN;
  395. else if(dir==5) return DIR_LEFTDOWN;
  396. else if(dir==6) return DIR_LEFT;
  397. else if(dir==7) return DIR_LEFTUP;
  398. }
  399.  
  400. //Move the specified object a set distance in a set direction
  401. //Walkable: Don't move onto a solid space
  402. //PreventOffScreen: Don't move off screen
  403. bool moveLink ( int dir, int dist, bool walkable, bool preventOffScreen )
  404. {
  405. //Can't move
  406. if ( walkable && !CanWalk(Link->X, Link->Y, dir, dist, false) )
  407. return false;
  408.  
  409. //Otherwise, check direction
  410. if ( dir == DIR_UP && (!preventOffScreen || Link->Y - dist > 0) )
  411. Link->Y -= dist;
  412. else if ( dir == DIR_DOWN && (!preventOffScreen || Link->Y + dist < SCREEN_HEIGHT) )
  413. Link->Y += dist;
  414. else if ( dir == DIR_LEFT && (!preventOffScreen || Link->X - dist > 0))
  415. Link->X -= dist;
  416. else if ( dir == DIR_RIGHT && (!preventOffScreen || Link->X + dist < SCREEN_WIDTH) )
  417. Link->X += dist;
  418. else
  419. return false;
  420.  
  421. return true;
  422. }
  423. bool move ( ffc this, int dir, int dist, bool walkable, bool preventOffScreen )
  424. {
  425. //Can't move
  426. if ( walkable && !CanWalk(this->X, this->Y, dir, dist, false) )
  427. return false;
  428.  
  429. //Otherwise, check direction
  430. if ( dir == DIR_UP && (!preventOffScreen || this->Y - dist > 0) )
  431. this->Y -= dist;
  432. else if ( dir == DIR_DOWN && (!preventOffScreen || this->Y + dist < SCREEN_HEIGHT) )
  433. this->Y += dist;
  434. else if ( dir == DIR_LEFT && (!preventOffScreen || this->X - dist > 0))
  435. this->X -= dist;
  436. else if ( dir == DIR_RIGHT && (!preventOffScreen || this->X + dist < SCREEN_WIDTH) )
  437. this->X += dist;
  438. else
  439. return false;
  440.  
  441. return true;
  442. }
  443. bool move ( npc enem, int dir, int dist, bool walkable, bool preventOffScreen )
  444. {
  445. //Can't move
  446. if ( walkable && !CanWalk(enem->X, enem->Y, dir, dist, false) )
  447. return false;
  448.  
  449. //Otherwise, check direction
  450. if ( dir == DIR_UP && (!preventOffScreen || enem->Y - dist > 0) )
  451. enem->Y -= dist;
  452. else if ( dir == DIR_DOWN && (!preventOffScreen || enem->Y + dist < SCREEN_HEIGHT) )
  453. enem->Y += dist;
  454. else if ( dir == DIR_LEFT && (!preventOffScreen || enem->X - dist > 0))
  455. enem->X -= dist;
  456. else if ( dir == DIR_RIGHT && (!preventOffScreen || enem->X + dist < SCREEN_WIDTH) )
  457. enem->X += dist;
  458. else
  459. return false;
  460.  
  461. return true;
  462. }
  463. bool move ( lweapon weap, int dir, int dist, bool walkable, bool preventOffScreen )
  464. {
  465. //Can't move
  466. if ( walkable && !CanWalk(weap->X, weap->Y, dir, dist, false) )
  467. return false;
  468.  
  469. //Otherwise, check direction
  470. if ( dir == DIR_UP && (!preventOffScreen || weap->Y - dist > 0) )
  471. weap->Y -= dist;
  472. else if ( dir == DIR_DOWN && (!preventOffScreen || weap->Y + dist < SCREEN_HEIGHT) )
  473. weap->Y += dist;
  474. else if ( dir == DIR_LEFT && (!preventOffScreen || weap->X - dist > 0))
  475. weap->X -= dist;
  476. else if ( dir == DIR_RIGHT && (!preventOffScreen || weap->X + dist < SCREEN_WIDTH) )
  477. weap->X += dist;
  478. else
  479. return false;
  480.  
  481. return true;
  482. }
  483. bool move ( eweapon weap, int dir, int dist, bool walkable, bool preventOffScreen )
  484. {
  485. //Can't move
  486. if ( walkable && !CanWalk(weap->X, weap->Y, dir, dist, false) )
  487. return false;
  488.  
  489. //Otherwise, check direction
  490. if ( dir == DIR_UP && (!preventOffScreen || weap->Y - dist > 0) )
  491. weap->Y -= dist;
  492. else if ( dir == DIR_DOWN && (!preventOffScreen || weap->Y + dist < SCREEN_HEIGHT) )
  493. weap->Y += dist;
  494. else if ( dir == DIR_LEFT && (!preventOffScreen || weap->X - dist > 0))
  495. weap->X -= dist;
  496. else if ( dir == DIR_RIGHT && (!preventOffScreen || weap->X + dist < SCREEN_WIDTH) )
  497. weap->X += dist;
  498. else
  499. return false;
  500.  
  501. return true;
  502. }
  503. bool move ( item theItem, int dir, int dist, bool walkable, bool preventOffScreen )
  504. {
  505. //Can't move
  506. if ( walkable && !CanWalk(theItem->X, theItem->Y, dir, dist, false) )
  507. return false;
  508.  
  509. //Otherwise, check direction
  510. if ( dir == DIR_UP && (!preventOffScreen || theItem->Y - dist > 0) )
  511. theItem->Y -= dist;
  512. else if ( dir == DIR_DOWN && (!preventOffScreen || theItem->Y + dist < SCREEN_HEIGHT) )
  513. theItem->Y += dist;
  514. else if ( dir == DIR_LEFT && (!preventOffScreen || theItem->X - dist > 0))
  515. theItem->X -= dist;
  516. else if ( dir == DIR_RIGHT && (!preventOffScreen || theItem->X + dist < SCREEN_WIDTH) )
  517. theItem->X += dist;
  518. else
  519. return false;
  520.  
  521. return true;
  522. }
  523.  
  524. //===============================================================================
  525. //Items and Equipment
  526. //===============================================================================
  527.  
  528. //Returns true if Link is pressing the button for an item
  529. bool pressingItem(int id)
  530. {
  531. return ( (GetEquipmentA()==id && Link->PressA)
  532. ||(GetEquipmentB()==id && Link->PressB) );
  533. }
  534.  
  535. //Returns the id of the highest level item of the given class that Link has acquired.
  536. //Unlike GetHighestLevelItem(), only applies to items Link owns
  537. int GetCurrentItem(int itemclass)
  538. {
  539. itemdata id;
  540. int ret = -1;
  541. int curlevel = -1000;
  542. for(int i = 0; i < MAX_ITEMS; i++){
  543. if(!Link->Item[i])
  544. continue;
  545. id = Game->LoadItemData(i);
  546. if(id->Family != itemclass)
  547. continue;
  548. if(id->Level > curlevel){
  549. curlevel = id->Level;
  550. ret = i;
  551. }
  552. }
  553. return ret;
  554. }
  555.  
  556. //Gives the specified item with hold up animation and optional fanfare
  557. //keep: Whether to actually give the item
  558. //twoHand: Use 1 or 2 hand animation
  559. //sfx: Whether to play item fanfare
  560. void holdUpItem(int id, bool keep, bool twoHand, bool sfx)
  561. {
  562. if ( sfx )
  563. Game->PlaySound(SFX_PICKUP);
  564. if ( twoHand )
  565. Link->Action = LA_HOLD2LAND;
  566. else
  567. Link->Action = LA_HOLD1LAND;
  568. Link->HeldItem = id;
  569.  
  570. //Give the item and its counter effects
  571. if(keep){
  572. Link->Item[id] = true;
  573. itemdata data = Game->LoadItemData(id);
  574. //Increase capacity
  575. if(data->MaxIncrement > 0 && data->Max > Game->MCounter[data->Counter]){
  576. Game->MCounter[data->Counter] = Min(Game->MCounter[data->Counter]+data->MaxIncrement, data->Max);
  577. }
  578. //Increase count
  579. if(data->Amount > 0)
  580. Game->Counter[data->Counter] = Min(Game->Counter[data->Counter]+data->Amount, Game->MCounter[data->Counter]);
  581. }
  582. }
  583.  
  584. //===============================================================================
  585. //Screen Freezing
  586. //===============================================================================
  587.  
  588. //WARNING: DO NOT USE IN AN FFC SCRIPT OR THE FFC WILL FREEZE ITSELF!
  589. //Use in global scripts only.
  590. void freezeScreen()
  591. {
  592. ffc freezeAll = Screen->LoadFFC(FFC_FREEZEALL);
  593. freezeAll->Data = CMB_FREEZEALL;
  594. ffc freezeFFC = Screen->LoadFFC(FFC_FREEZEFFC);
  595. freezeFFC->Data = CMB_FREEZEFFC;
  596. }
  597.  
  598. void unfreezeScreen()
  599. {
  600. ffc freezeAll = Screen->LoadFFC(FFC_FREEZEALL);
  601. freezeAll->Data = CMB_BLANK;
  602. ffc freezeFFC = Screen->LoadFFC(FFC_FREEZEFFC);
  603. freezeFFC->Data = CMB_BLANK;
  604. }
  605.  
  606. //===============================================================================
  607. //Weapons
  608. //===============================================================================
  609.  
  610. //Toggles weapon blockability by adjusting its direction
  611. int toggleBlock (int dir)
  612. {
  613. if(dir == DIR_UP)
  614. return 8;
  615. if(dir == DIR_DOWN)
  616. return 12;
  617. if(dir == DIR_LEFT)
  618. return 14;
  619. if(dir == DIR_RIGHT)
  620. return 10;
  621. if(dir == DIR_LEFTUP)
  622. return 15;
  623. if(dir == DIR_RIGHTUP)
  624. return 9;
  625. if(dir == DIR_LEFTDOWN)
  626. return 13;
  627. if(dir == DIR_RIGHTDOWN)
  628. return 11;
  629.  
  630. if(dir==8)
  631. return DIR_UP;
  632. if(dir==9)
  633. return DIR_RIGHTUP;
  634. if(dir==10)
  635. return DIR_RIGHT;
  636. if(dir==11)
  637. return DIR_RIGHTDOWN;
  638. if(dir==12)
  639. return DIR_DOWN;
  640. if(dir==13)
  641. return DIR_LEFTDOWN;
  642. if(dir==14)
  643. return DIR_LEFT;
  644. if(dir==15)
  645. return DIR_LEFTUP;
  646.  
  647. return dir;
  648. }
  649.  
  650. //Get the correct flip for a 4-dir weapon based on its direction
  651. int getFlip(int dir)
  652. {
  653. if ( dir == DIR_UP )
  654. return FLIP_NO;
  655. if ( dir == DIR_DOWN )
  656. return FLIP_B;
  657. if ( dir == DIR_LEFT )
  658. return ROTATE_CCW;
  659. if ( dir == DIR_RIGHT )
  660. return ROTATE_CW;
  661. return -1;
  662. }
  663.  
  664. //Sets the flip for a 4-dir weapon based on a single sprite
  665. void setFlip ( lweapon weapon )
  666. {
  667. int flip = getFlip(weapon->Dir);
  668. if(flip >= 0)
  669. weapon->Flip = flip;
  670. }
  671. void setFlip ( eweapon weapon ){
  672. int flip = getFlip(weapon->Dir);
  673. if(flip >= 0)
  674. weapon->Flip = flip;
  675. }
  676.  
  677. //Sets flip for a 4-dir sword based on two sprites (up and right)
  678. void setFlipSword ( lweapon weapon ){
  679. if ( weapon->Dir >= DIR_LEFT )
  680. weapon->Tile++;
  681. if ( weapon->Dir == DIR_DOWN )
  682. weapon->Flip = FLIP_B;
  683. else if ( weapon->Dir == DIR_LEFT )
  684. weapon->Flip = FLIP_H;
  685. }
  686. void setFlipSword ( eweapon weapon ){
  687. if ( weapon->Dir >= DIR_LEFT )
  688. weapon->Tile++;
  689. if ( weapon->Dir == DIR_DOWN )
  690. weapon->Flip = FLIP_B;
  691. else if ( weapon->Dir == DIR_LEFT )
  692. weapon->Flip = FLIP_H;
  693. }
  694.  
  695. //===============================================================================
  696. //Other
  697. //===============================================================================
  698.  
  699. void permaSecrets(){
  700. Screen->TriggerSecrets();
  701. Screen->State[ST_SECRET] = true;
  702. }
  703.  
  704. void tempSecrets(){
  705. Screen->TriggerSecrets();
  706. Screen->State[ST_SECRET] = false;
  707. }
  708.  
  709. //Makes secrets permanent if "Secrets are temporary" is not checked
  710. void screenSecrets(){
  711. Screen->TriggerSecrets();
  712. if(!(Screen->Flags[SF_SECRETS]&2)){
  713. Screen->State[ST_SECRET] = true;
  714. }
  715. }
  716.  
  717. bool WaitframeCheckScreenChange(){
  718. int old_dmap_screen = Game->GetCurDMapScreen();
  719. int old_dmap = Game->GetCurDMap();
  720. Waitframe();
  721. return (old_dmap!=Game->GetCurDMap() || old_dmap_screen!=Game->GetCurDMapScreen());
  722. }
  723.  
  724. bool WaitframeCheckWarp(){
  725. return ( WaitframeCheckScreenChange() && !(Link->Action==LA_SCROLLING));
  726. }
  727.  
  728. //Draw an inverted circle (fill whole screen except circle)
  729. void InvertedCircle(int bitmapID, int layer, int x, int y, int radius, int scale, int fillcolor){
  730. Screen->SetRenderTarget(bitmapID); //Set the render target to the bitmap.
  731. Screen->Rectangle(layer, 0, 0, 256, 176, fillcolor, 1, 0, 0, 0, true, 128); //Cover the screen
  732. Screen->Circle(layer, x, y, radius, 0, scale, 0, 0, 0, true, 128); //Draw a transparent circle.
  733. Screen->SetRenderTarget(RT_SCREEN); //Set the render target back to the screen.
  734. Screen->DrawBitmap(layer, bitmapID, 0, 0, 256, 176, 0, 56, 256, 176, 0, true); //Draw the bitmap
  735. }
  736.  
  737. bool LinkOnComboType(int type){
  738. return(Screen->ComboT[ComboAt(CenterLinkX(), CenterLinkY())] == type);
  739. }
  740.  
  741. bool LinkOnTallGrass(){
  742. return ( LinkOnComboType(CT_TALLGRASS)
  743. || LinkOnComboType(CT_TALLGRASSC)
  744. || LinkOnComboType(CT_TALLGRASSNEXT)
  745. );
  746. }
  747.  
  748. void closingWipe(int wipetime){
  749. for(int i = wipetime; i > 0; i--){
  750. InvertedCircle(4, 6, CenterLinkX(), CenterLinkY(), Floor(300/wipetime)*i, 1, 15);
  751. WaitNoAction();
  752. }
  753. }
  754. void openingWipe(int wipetime){
  755. for(int i = 0; i < wipetime; i++){
  756. InvertedCircle(4, 6, CenterLinkX(), CenterLinkY(), Floor(300/wipetime)*i, 1, 15);
  757. WaitNoAction();
  758. }
  759. }
  760.  
  761. //Get the color value given CSet and in-CSet color
  762. int color(int cset, int csetColor){
  763. return (cset*16) + csetColor;
  764. }
  765.  
  766. //Simulates a 2D array
  767. //Returns the index of an array given row, column, and number of rows
  768. int arr2D ( int row, int col, int numCols ){
  769. return (row * numCols) + col;
  770. }
  771.  
  772. //Extracted this method from ffcscript.zh for common usage
  773. //If force is true, takes over the last FFC even if it's used
  774. ffc loadUnusedFFC(bool force){
  775. ffc theFFC;
  776. for(int i = FFCS_MIN_FFC; i <= FFCS_MAX_FFC; i++){
  777. theFFC=Screen->LoadFFC(i); //Check each FFC
  778.  
  779. if ( ffcIsBlank(theFFC) )
  780. return theFFC; //Return it
  781.  
  782. if ( force && i == FFCS_MAX_FFC ) //Force last FFC
  783. return theFFC;
  784. }
  785.  
  786. //No FFC found; return an invalid one
  787. ffc invalidFFC;
  788. return invalidFFC;
  789. }
  790.  
  791. //Tells whether an FFC is blank and unused
  792. bool ffcIsBlank(ffc this){
  793. return ( this->Script == 0 && //If not running a script
  794. ( this->Data == 0 || this->Data == FFCS_INVISIBLE_COMBO)); //And blank combo
  795. }
  796.  
  797. //Draws the given time in frames as minutes and seconds
  798. //Taken from "Hot Rooms" by Zecora
  799. void drawTime(int layer, int x, int y, int frames){
  800. drawTime(layer, x, y, FONT_S, COLOR_WHITE, COLOR_BLACK, TF_NORMAL, frames);
  801. }
  802.  
  803. void drawTime(int layer, int x, int y, int font, int color, int bgcolor, int format, int frames){
  804. int seconds = Div(frames, 60); //Total seconds
  805. int minutes = Div(seconds, 60); //Total minutes
  806. seconds %= 60; //Remaining seconds (0 - 59)
  807.  
  808. int string[5]; //Create an array of characters.
  809. itoa(string, 0, minutes); //Add the minutes to the array.
  810. string[strlen(string)] = ':'; //Add the : after the minutes.
  811. if(seconds < 10) //Single-digit seconds: add '0' before count
  812. string[strlen(string)] = '0';
  813. itoa(string, strlen(string), seconds);
  814. Screen->DrawString(layer, x, y, font, color, bgcolor, format, string, 128);
  815. }
  816.  
  817. // Has a 1 in n chance of returning true
  818. bool nChance(int chance)
  819. {
  820. return Rand(chance) == 0;
  821. }
  822.  
  823. // Given integer n, has an n% chance of returning true.
  824. bool percentChance(int chance)
  825. {
  826. return Rand(100) < chance;
  827. }
  828.  
  829. //===============================================================================
  830. //Debug
  831. //===============================================================================
  832.  
  833. //Shortcut for drawInteger for debug output
  834. //Each debug item should have a unique "num" (match between value and label)
  835. void debugValue ( int num, float value ){
  836. debugValue(num, value, 0);
  837. }
  838.  
  839. void debugValue ( int num, float value, int places ){
  840. places = Clamp(places, 0, 4);
  841. Screen->DrawInteger(6, 100, 2+10*num, FONT_S, COLOR_WHITE, COLOR_BLACK, -1, -1, value, places, OP_OPAQUE);
  842. }
  843.  
  844. void debugValue( int num, bool value){
  845. int trueString[] = "true";
  846. int falseString[] = "false";
  847. Screen->DrawString(6, 100, 2+10*num, FONT_S, COLOR_WHITE, COLOR_BLACK, TF_NORMAL, Cond(value, trueString, falseString), OP_OPAQUE);
  848. }
  849.  
  850. void debugLabel ( int num, int string ){
  851. Screen->DrawString(6, 2, 2+10*num, FONT_S, COLOR_WHITE, COLOR_BLACK, TF_NORMAL, string, OP_OPAQUE);
  852. }
  853.  
  854. //Both functions in one call, matching "num"
  855. void debug ( int num, int string, float value ){
  856. debugLabel(num, string);
  857. debugValue(num, value, 0);
  858. }
  859. void debug ( int num, int string, float value, int places ){
  860. debugLabel(num, string);
  861. debugValue(num, value, places);
  862. }
  863. void debug ( int num, int string, bool value ){
  864. debugLabel(num, string);
  865. debugValue(num, value);
  866. }
  867.  
  868. bool SelectPressInput(int input){
  869. if(input == 0) return Link->PressA;
  870. else if(input == 1) return Link->PressB;
  871. else if(input == 2) return Link->PressL;
  872. else if(input == 3) return Link->PressR;
  873. }
  874. void SetInput(int input, bool state){
  875. if(input == 0) Link->InputA = state;
  876. else if(input == 1) Link->InputB = state;
  877. else if(input == 2) Link->InputL = state;
  878. else if(input == 3) Link->InputR = state;
  879. }
  880.  
  881. ffc script stepMsg
  882. {
  883. void run(int m, int sens)
  884. {
  885. if ( !sens ) sens = 8;
  886. while(1)
  887. {
  888. if ( DistX(this, sens) )
  889. {
  890. if ( DistY(this, sens) )
  891. {
  892. break;
  893. }
  894. }
  895. Waitframe();
  896. }
  897. Screen->Message(m);
  898. }
  899. }
  900. ffc script EnemyMusic
  901. {
  902. void run(int bmidi, int nmidi)
  903. {
  904. while(true)
  905. {
  906. if (Screen->NumNPCs() != 0)
  907. {
  908. Game->PlayMIDI(bmidi);
  909. }
  910. else
  911. {
  912. Game->PlayMIDI(nmidi);
  913. }
  914. Waitframe();
  915. }
  916. }
  917. }
  918.  
  919. const int EQ_QUAKE_TIME = 90;
  920.  
  921. ffc script Earthquake
  922. {
  923. void run(int wait)
  924. {
  925. Waitframes(wait);
  926. Screen->Quake = EQ_QUAKE_TIME;
  927. Link->SwordJinx = EQ_QUAKE_TIME;
  928. Link->ItemJinx = EQ_QUAKE_TIME;
  929. }
  930. }
  931. item script itemBundle
  932. {
  933. void run(int item1, int item2, int item3, int item4, int item5, int item6, int item7, int item8)
  934. {
  935. if(item1 > 0)
  936. Link->Item[item1] = true;
  937. if(item2 > 0)
  938. Link->Item[item2] = true;
  939. if(item3 > 0)
  940. Link->Item[item3] = true;
  941. if(item4 > 0)
  942. Link->Item[item4] = true;
  943. if(item5 > 0)
  944. Link->Item[item5] = true;
  945. if(item6 > 0)
  946. Link->Item[item6] = true;
  947. if(item7 > 0)
  948. Link->Item[item7] = true;
  949. if(item8 > 0)
  950. Link->Item[item8] = true;
  951.  
  952. // Display Item pickup message?
  953. if(item1 < 0)
  954. {
  955. Screen->Message(item1 * -1);
  956. }
  957. }//!End void run()
  958. }//!End item script itemBundle
  959.  
  960. bool OnPlatform (ffc this){
  961. if(CenterLinkX() < this->X) return false;
  962. else if(CenterLinkX() >= this->X + this->EffectWidth) return false;
  963. else if(CenterLinkY() < this->Y) return false;
  964. else if(CenterLinkY() >= this->Y + this->EffectHeight) return false;
  965. else return true;
  966. }
  967.  
  968.  
  969. ffc script PermanentTieredSecrets
  970. {
  971. void run(int D, int Layer, int NumStates){
  972. //Triggers the number of screen secrets stored in Screen->D when you enter the screen
  973. if(Screen->D[D]>0){
  974. for(int i=0; i<Screen->D[D]; i++){
  975. Screen->TriggerSecrets();
  976. }
  977. }
  978. //Saves the combo position and combo under the FFC
  979. int ComboPos = ComboAt(this->X+8, this->Y+8);
  980. int Combo;
  981. if(Layer>0)
  982. Combo = GetLayerComboD(Layer, ComboPos);
  983. else if(Layer==0)
  984. Combo = Screen->ComboD[ComboPos];
  985. while(true){
  986. //Detects if the combo under the FFC changes and increases Screen->D
  987. if(Layer>0&&GetLayerComboD(Layer, ComboPos)!=Combo){
  988. Combo = GetLayerComboD(Layer, ComboPos);
  989. Screen->D[D]++;
  990. }
  991. else if(Layer==0&&Screen->ComboD[ComboPos]!=Combo){
  992. Combo = Screen->ComboD[ComboPos];
  993. Screen->D[D]++;
  994. }
  995. //Wraps Screen->D if NumStates is set, otherwise caps Screen->D at 100
  996. if(NumStates>0&&Screen->D[D]>=NumStates)
  997. Screen->D[D] -= NumStates;
  998. else if(NumStates==0&&Screen->D[D]>100){
  999. Screen->D[D] = 100;
  1000. }
  1001. Waitframe();
  1002. }
  1003. }
  1004. }
  1005.  
  1006. const int CUTSCENETRIGGER_SHOW_HITBOXES = 0; //For debugging problems with the script's hitboxes, set this to 1.
  1007. const int C_CUTSCENETRIGGER_HITBOX = 0x01; //Color for the debug hitboxes
  1008.  
  1009. const int D_CUTSCENETRIGGER = 0; //Screen->D used for cutscene triggers
  1010.  
  1011. //D0: The DMap to warp to for the cutscene
  1012. //D1: The screen to warp to IN DECIMAL. Screens in ZQuest are numbered in hex but FFCs only take arguments
  1013. // in decimal, so you'll have to convert.
  1014. //D2: Width of the trigger hitbox
  1015. //D3: Height of the trigger hitbox
  1016. //D4: Set this to a number 1-17 to make the cutscene only play once. By giving FFCs different D4 arguments,
  1017. // you can have multiple triggers for different permanent cutscenes on a screen.
  1018. //D5: If you want the trigger to check for a flag under Link, set this to the number of the flag.
  1019. // If you want it to check for an item, set this to a negative Item ID.
  1020. //D6: The X position to try to walk Link to. 0 for no target point.
  1021. //D7: The Y position to try to walk Link to. 0 for no target point.
  1022. ffc script CutsceneTrigger{
  1023. void run(int newDMap, int newScreen, int w, int h, int oneUse, int checkItemorFlag, int targetX, int targetY){
  1024. int dbit;
  1025. if(oneUse>0){
  1026. dbit = 1<<(oneUse-1);
  1027. }
  1028. //If Link starts standing on the cutscene hitbox, wait for him to step off
  1029. while(Link->X+8 >= this->X && Link->X+8 <= this->X+w-1 && Link->Y+12 >= this->Y && Link->Y+12 <= this->Y+h-1 ){
  1030. if(CUTSCENETRIGGER_SHOW_HITBOXES){
  1031. Screen->Rectangle(6, this->X-1, this->Y-1, this->X+w-1+1, this->Y+h-1+1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
  1032. Screen->Rectangle(6, this->X, this->Y, this->X+w-1, this->Y+h-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 128);
  1033. Screen->Rectangle(6, this->X+1, this->Y+1, this->X+w-1-1, this->Y+h-1-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, true, 64);
  1034. }
  1035. Waitframe();
  1036. }
  1037. //Check if the cutscene has already been triggered
  1038. if(oneUse&&Screen->D[D_CUTSCENETRIGGER]&dbit){
  1039. Quit();
  1040. }
  1041. while(true){
  1042. if(CUTSCENETRIGGER_SHOW_HITBOXES){
  1043. Screen->Rectangle(6, this->X-1, this->Y-1, this->X+w-1+1, this->Y+h-1+1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
  1044. Screen->Rectangle(6, this->X, this->Y, this->X+w-1, this->Y+h-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 128);
  1045. Screen->Rectangle(6, this->X+1, this->Y+1, this->X+w-1-1, this->Y+h-1-1, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, false, 64);
  1046. }
  1047. //Find if Link has collided with the trigger hitbox
  1048. if(Link->X+8 >= this->X && Link->X+8 <= this->X+w-1 && Link->Y+12 >= this->Y && Link->Y+12 <= this->Y+h-1 ){
  1049. if(CUTSCENETRIGGER_SHOW_HITBOXES){
  1050. Screen->Rectangle(6, this->X+2, this->Y+2, this->X+w-1-2, this->Y+h-1-2, C_CUTSCENETRIGGER_HITBOX, 1, 0, 0, 0, true, 64);
  1051. }
  1052. //If Link meets one the requirements to trigger the cutscene, break out of the loop
  1053. if(checkItemorFlag==0){
  1054. break;
  1055. }
  1056. //If the checkItemorFlag argument is negative, check for an item
  1057. else if(checkItemorFlag<0){
  1058. if(Link->Item[Abs(checkItemorFlag)])
  1059. break;
  1060. }
  1061. //Else check for a screen flag
  1062. else if(ComboFI(Link->X+8, Link->Y+12, checkItemorFlag)){
  1063. break;
  1064. }
  1065. }
  1066. Waitframe();
  1067. }
  1068. if(targetX>0||targetY>0){
  1069. //Move Link either until he's in position or 4 seconds have passed
  1070. for(int i=0; i<=240&&(Link->X!=targetX||Link->Y!=targetY); i++){
  1071. //Prevent moving around while moving Link into position
  1072. Link->InputStart = false; Link->PressStart = false;
  1073. Link->InputMap = false; Link->PressMap = false;
  1074. NoAction();
  1075.  
  1076. //Apply inputs that should be active
  1077. if(Abs(Link->X-targetX)<=2){
  1078. Link->X = targetX;
  1079. }
  1080. else{
  1081. if(Link->X<targetX)
  1082. Link->InputRight = true;
  1083. else if(Link->X>targetX)
  1084. Link->InputLeft = true;
  1085. }
  1086. if(Abs(Link->Y-targetY)<=2){
  1087. Link->Y = targetY;
  1088. }
  1089. else{
  1090. if(Link->Y<targetY)
  1091. Link->InputDown = true;
  1092. else if(Link->Y>targetY)
  1093. Link->InputUp = true;
  1094. }
  1095. Waitframe();
  1096. }
  1097. }
  1098. if(oneUse){
  1099. Screen->D[D_CUTSCENETRIGGER] |= dbit;
  1100. }
  1101. Link->PitWarp(newDMap, newScreen);
  1102. }
  1103. }
  1104.  
  1105. int MooshPit[16];
  1106. const int _MP_LASTX = 0;
  1107. const int _MP_LASTY = 1;
  1108. const int _MP_LASTDMAP = 2;
  1109. const int _MP_LASTSCREEN = 3;
  1110. const int _MP_ENTRYX = 4;
  1111. const int _MP_ENTRYY = 5;
  1112. const int _MP_ENTRYDMAP = 6;
  1113. const int _MP_ENTRYSCREEN = 7;
  1114. const int _MP_FALLX = 8;
  1115. const int _MP_FALLY = 9;
  1116. const int _MP_FALLTIMER = 10;
  1117. const int _MP_FALLSTATE = 11;
  1118. const int _MP_DAMAGETYPE = 12;
  1119. const int _MP_SLIDETIMER = 13;
  1120.  
  1121. const int MOOSHPIT_NO_GRID_SNAP = 1; //Set to 1 to prevent Link's falling sprite from snapping to the combo grid.
  1122. const int MOOSHPIT_ENABLE_SLIDEYPITS = 1; //Set to 1 if Link should slide into pits he's partially on
  1123. const int MOOSHPIT_NO_MOVE_WHILE_FALLING = 1; //Set to 1 if you don't want Link able to move while falling
  1124. const int MOOSHPIT_NO_REENTER_STAIRS = 1; //Set to 1 to prevent Link reentering stairs when respawning from a pit. This uses an FFC slot to run the script
  1125. const int MOOSHPIT_STUN_ENEMIES_WHILE_FALLING = 1; //Set to 1 to stun stunnable enemies while falling in a pit
  1126.  
  1127. const int CT_HOLELAVA = 128;
  1128. const int CF_LAVA = 122;
  1129.  
  1130. const int SPR_FALLHOLE = 126; //Sprite for Link falling in a hole
  1131. const int SPR_FALLLAVA = 99; //Sprite for Link falling in lava
  1132.  
  1133. const int SFX_FALLHOLE = 38; //Sound for falling in a hole
  1134. const int SFX_FALLLAVA = 85; //Sound for falling in lava
  1135.  
  1136. const int DAMAGE_FALLHOLE = 8; //How much damage pits deal (1/2 heart default)
  1137. const int DAMAGE_FALLLAVA = 16; //How much damage lava deals (1 heart default)
  1138.  
  1139. const int FFC_MOOSHPIT_AUTOWARPA = 32;
  1140. const int CMB_MOOSHPIT_AUTOWARPA = 2891;
  1141. const int SF_MISC_MOOSHPITWARP = 2;
  1142.  
  1143. const int MOOSHPIT_MIN_FALL_TIME = 60; //Minimum time for the pit's fall animation, to prevent repeated falling in pits
  1144. const int MOOSHPIT_EXTRA_FALL_TIME = 0; //Extra frames at the end of the falling animation before Link respawns
  1145.  
  1146. //Width and height of Link's hitbox for colliding with pits
  1147. const int MOOSHPIT_LINKHITBOXWIDTH = 16;
  1148. const int MOOSHPIT_LINKHITBOXHEIGHT = 16;
  1149.  
  1150. //Width and height of Link's hitbox for colliding with pits/lava in sideview
  1151. const int MOOSHPIT_SIDEVIEW_LINKHITBOXWIDTH = 2;
  1152. const int MOOSHPIT_SIDEVIEW_LINKHITBOXHEIGHT = 2;
  1153.  
  1154. const int MOOSHPIT_SLIDEYPIT_FREQ = 3; //Link will be pushed into slideypits every 1/n frames
  1155. const int MOOSHPIT_SLIDEYPIT_MAXTIME = 20; //Link will be pushed into slideypits more intensely after n frames
  1156. const int MOOSHPIT_SLIDEYPIT_ACCELFREQ = 8; //How often Link accelerates when falling in the pit
  1157.  
  1158. int MooshPit_OnPit(int LinkX, int LinkY, bool countFFCs){
  1159. if(Link->Action==LA_FROZEN||Link->Action==LA_RAFTING||Link->Action==LA_INWIND)
  1160. return -1;
  1161.  
  1162. if(countFFCs){
  1163. if(MooshPit_OnFFC(LinkX, LinkY))
  1164. return -1;
  1165. }
  1166.  
  1167. bool sideview;
  1168. if(Screen->Flags[SF_ROOMTYPE]&100b)
  1169. sideview = true;
  1170. //wew lad
  1171. int width = MOOSHPIT_LINKHITBOXWIDTH;
  1172. int height = MOOSHPIT_LINKHITBOXHEIGHT;
  1173.  
  1174. int total;
  1175. int solidTotal;
  1176.  
  1177. for(int x=0; x<=1; x++){
  1178. for(int y=0; y<=1; y++){
  1179. int X; int Y;
  1180. if(sideview){ //Hitbox functions differently in sideview
  1181. width = MOOSHPIT_SIDEVIEW_LINKHITBOXWIDTH;
  1182. height = MOOSHPIT_SIDEVIEW_LINKHITBOXHEIGHT;
  1183. X = Floor(LinkX+7-width/2+(width-1)*x)+1;
  1184. Y = Floor(LinkY+7-height/2+(height-1)*y)+1;
  1185. }
  1186. else{
  1187. X = Floor(LinkX+7-width/2+(width-1)*x)+1;
  1188. Y = Floor(LinkY+11-height/2+(height-1)*y)+1;
  1189. }
  1190.  
  1191. //If one corner of Link's hitbox is on a pit, flag that corner as covered
  1192. if(Screen->ComboT[ComboAt(X, Y)]==CT_HOLELAVA){
  1193. total |= 1<<(1+(x+y*2));
  1194. }
  1195. //If Link is on a solid combo, count that corner as a pit
  1196. if(Screen->isSolid(X, Y)){
  1197. solidTotal |= 1<<(x+y*2);
  1198. }
  1199. }
  1200. }
  1201. if(total>0) //Assuming Link is on at least one actual pit, add up the solid and nonsolid pits
  1202. return (total>>1)|(solidTotal<<4);
  1203. return -1;
  1204. }
  1205.  
  1206. bool MooshPit_OnFFC(int LinkX, int LinkY){
  1207. for(int i=1; i<=32; i++){ //Cycle through every FFC
  1208. ffc f = Screen->LoadFFC(i);
  1209. //Check if the FFC is solid
  1210. if(f->Data>0&&!f->Flags[FFCF_CHANGER]&&!f->Flags[FFCF_ETHEREAL]){
  1211. //Check if Link collides with the FFC
  1212. if(RectCollision(LinkX+4, LinkY+9, LinkX+11, LinkY+14, f->X, f->Y, f->X+f->EffectWidth-1, f->Y+f->EffectHeight-1)){
  1213. return true;
  1214. }
  1215. }
  1216. }
  1217. //If Link doesn't collide with any FFC, return false
  1218. return false;
  1219. }
  1220.  
  1221. void MooshPit_StunEnemies(){
  1222. for(int i=Screen->NumNPCs(); i>=1; i--){ //Cycle through every enemy
  1223. npc n = Screen->LoadNPC(i);
  1224. //Make it so the enemy's stun never falls below 1
  1225. n->Stun = Max(n->Stun, 1);
  1226. }
  1227. }
  1228.  
  1229. void MooshPit_Init(){
  1230. MooshPit[_MP_LASTX] = Link->X;
  1231. MooshPit[_MP_LASTY] = Link->Y;
  1232. MooshPit[_MP_LASTDMAP] = Game->GetCurDMap();
  1233. MooshPit[_MP_LASTSCREEN] = Game->GetCurDMapScreen();
  1234. MooshPit[_MP_ENTRYX] = Link->X;
  1235. MooshPit[_MP_ENTRYY] = Link->Y;
  1236. MooshPit[_MP_ENTRYDMAP] = Game->GetCurDMap();
  1237. MooshPit[_MP_ENTRYSCREEN] = Game->GetCurDMapScreen();
  1238. MooshPit[_MP_FALLSTATE] = 0;
  1239. MooshPit[_MP_FALLTIMER] = 0;
  1240. Link->CollDetection = true;
  1241. Link->Invisible = false;
  1242. }
  1243.  
  1244. void MooshPit_Update(){
  1245. int i;
  1246. bool isWarp;
  1247. if(Screen->Flags[SF_MISC]&(1<<SF_MISC_MOOSHPITWARP))
  1248. isWarp = true;
  1249.  
  1250. bool sideview;
  1251. if(Screen->Flags[SF_ROOMTYPE]&100b)
  1252. sideview = true;
  1253.  
  1254. if(Link->Action!=LA_SCROLLING){
  1255. //Update the entry point whenever the screen changes
  1256. if(MooshPit[_MP_ENTRYDMAP]!=Game->GetCurDMap()||MooshPit[_MP_ENTRYSCREEN]!=Game->GetCurDMapScreen()){
  1257. MooshPit[_MP_ENTRYX] = Link->X;
  1258. MooshPit[_MP_ENTRYY] = Link->Y;
  1259. MooshPit[_MP_ENTRYDMAP] = Game->GetCurDMap();
  1260. MooshPit[_MP_ENTRYSCREEN] = Game->GetCurDMapScreen();
  1261. }
  1262.  
  1263. if(MooshPit[_MP_FALLSTATE]==0){ //Not falling in pit
  1264. int onPit = MooshPit_OnPit(Link->X, Link->Y, true);
  1265. //Check if slidey pits are enabled and it's not sideview
  1266. if(MOOSHPIT_ENABLE_SLIDEYPITS&&!IsSideview()){
  1267. if(Link->Z<=0&&onPit>-1){ //If Link is partially on a pit
  1268. int slideVx; int slideVy;
  1269. int reps = 1;
  1270. //Check if it's a frame Link should be moved
  1271. if(MooshPit[_MP_SLIDETIMER]%MOOSHPIT_SLIDEYPIT_FREQ==0||MooshPit[_MP_SLIDETIMER]>=MOOSHPIT_SLIDEYPIT_MAXTIME){
  1272. if((onPit&0111b)==0111b){ //Going up-left
  1273. slideVx = -1;
  1274. slideVy = -1;
  1275. }
  1276. else if((onPit&1011b)==1011b){ //Going up-right
  1277. slideVx = 1;
  1278. slideVy = -1;
  1279. }
  1280. else if((onPit&1101b)==1101b){ //Going down-left
  1281. slideVx = -1;
  1282. slideVy = 1;
  1283. }
  1284. else if((onPit&1110b)==1110b){ //Going down-right
  1285. slideVx = 1;
  1286. slideVy = 1;
  1287. }
  1288. else if((onPit&0011b)==0011b){ //Going up
  1289. slideVy = -1;
  1290. }
  1291. else if((onPit&1100b)==1100b){ //Going down
  1292. slideVy = 1;
  1293. }
  1294. else if((onPit&0101b)==0101b){ //Going left
  1295. slideVx = -1;
  1296. }
  1297. else if((onPit&1010b)==1010b){ //Going right
  1298. slideVx = 1;
  1299. }
  1300. else if((onPit&0001b)==0001b){ //Going up-left
  1301. slideVx = -1;
  1302. slideVy = -1;
  1303. }
  1304. else if((onPit&0010b)==0010b){ //Going up-right
  1305. slideVx = 1;
  1306. slideVy = -1;
  1307. }
  1308. else if((onPit&0100b)==0100b){ //Going down-left
  1309. slideVx = -1;
  1310. slideVy = 1;
  1311. }
  1312. else if((onPit&1000b)==1000b){ //Going down-right
  1313. slideVx = 1;
  1314. slideVy = 1;
  1315. }
  1316.  
  1317. //DEBUG DRAWS
  1318. //VX
  1319. // Screen->DrawInteger(6, 0, 0, FONT_Z1, 0x01, 0x0F, -1, -1, slideVx, 0, 128);
  1320. //VY
  1321. // Screen->DrawInteger(6, 0, 8, FONT_Z1, 0x01, 0x0F, -1, -1, slideVy, 0, 128);
  1322. //ONPIT BITS
  1323. // Screen->DrawInteger(6, 0, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&1000b)>>3, 0, 128);
  1324. // Screen->DrawInteger(6, 8, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&0100b)>>2, 0, 128);
  1325. // Screen->DrawInteger(6, 16, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&0010b)>>1, 0, 128);
  1326. // Screen->DrawInteger(6, 24, 16, FONT_Z1, 0x01, 0x0F, -1, -1, (onPit&0001b), 0, 128);
  1327.  
  1328. //If Link is over the max slide time, increase the speed every 4 frames
  1329. if(MooshPit[_MP_SLIDETIMER]>=MOOSHPIT_SLIDEYPIT_MAXTIME)
  1330. reps += Floor((MooshPit[_MP_SLIDETIMER]-MOOSHPIT_SLIDEYPIT_MAXTIME)/MOOSHPIT_SLIDEYPIT_ACCELFREQ);
  1331. }
  1332.  
  1333. for(i=0; i<reps; i++){
  1334. if(slideVx<0&&CanWalk(Link->X, Link->Y, DIR_LEFT, 1, false)){
  1335. Link->X--;
  1336. }
  1337. else if(slideVx>0&&CanWalk(Link->X, Link->Y, DIR_RIGHT, 1, false)){
  1338. Link->X++;
  1339. }
  1340. if(slideVy<0&&CanWalk(Link->X, Link->Y, DIR_UP, 1, false)){
  1341. Link->Y--;
  1342. }
  1343. else if(slideVy>0&&CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)){
  1344. Link->Y++;
  1345. }
  1346. }
  1347. MooshPit[_MP_SLIDETIMER]++;
  1348. }
  1349. else{
  1350. MooshPit[_MP_SLIDETIMER] = 0;
  1351. }
  1352. }
  1353. if(onPit>-1){
  1354. //Combine solid combo bits with pit bits
  1355. onPit |= (onPit>>4);
  1356. //Remove non pit bits
  1357. onPit &= 1111b;
  1358. }
  1359. if(Link->Z<=0&&onPit==15){ //If Link steps on a pit
  1360. int underLink;
  1361. if(!sideview){
  1362. underLink = ComboAt(Link->X+8, Link->Y+12);
  1363. if(Screen->ComboT[underLink]!=CT_HOLELAVA){
  1364. for(i=0; i<4; i++){
  1365. underLink = ComboAt(Link->X+15*(i%2), Link->Y+8+7*Floor(i/2));
  1366. if(Screen->ComboT[underLink]==CT_HOLELAVA)
  1367. break;
  1368. }
  1369. }
  1370. }
  1371. else{
  1372. underLink = ComboAt(Link->X+8, Link->Y+8);
  1373. if(Screen->ComboT[underLink]!=CT_HOLELAVA){
  1374. for(i=0; i<4; i++){
  1375. underLink = ComboAt(Link->X+15*(i%2), Link->Y+15*Floor(i/2));
  1376. if(Screen->ComboT[underLink]==CT_HOLELAVA)
  1377. break;
  1378. }
  1379. }
  1380. }
  1381.  
  1382. lweapon fall;
  1383.  
  1384. //Check if the combo is lava
  1385. if(ComboFI(underLink, CF_LAVA)){
  1386. //Play sound and display animation
  1387. Game->PlaySound(SFX_FALLLAVA);
  1388. fall = CreateLWeaponAt(LW_SCRIPT10, Link->X, Link->Y);
  1389. if(!MOOSHPIT_NO_GRID_SNAP){
  1390. fall->X = ComboX(underLink);
  1391. fall->Y = ComboY(underLink);
  1392. }
  1393. fall->UseSprite(SPR_FALLLAVA);
  1394. fall->CollDetection = false;
  1395. fall->DeadState = fall->ASpeed*fall->NumFrames;
  1396.  
  1397. //Mark as lava damage
  1398. MooshPit[_MP_DAMAGETYPE] = 1;
  1399. }
  1400. //Otherwise it's a pit
  1401. else{
  1402. //Play sound and display animation
  1403. Game->PlaySound(SFX_FALLHOLE);
  1404. fall = CreateLWeaponAt(LW_SCRIPT10, Link->X, Link->Y);
  1405. if(!MOOSHPIT_NO_GRID_SNAP){
  1406. fall->X = ComboX(underLink);
  1407. fall->Y = ComboY(underLink);
  1408. if(isWarp){
  1409. Link->X = ComboX(underLink);
  1410. Link->Y = ComboY(underLink);
  1411. }
  1412. }
  1413. fall->UseSprite(SPR_FALLHOLE);
  1414. fall->CollDetection = false;
  1415. fall->DeadState = fall->ASpeed*fall->NumFrames;
  1416.  
  1417. //Mark as hole damage
  1418. MooshPit[_MP_DAMAGETYPE] = 0;
  1419. }
  1420.  
  1421. MooshPit[_MP_FALLX] = Link->X;
  1422. MooshPit[_MP_FALLY] = Link->Y;
  1423.  
  1424. //Cooldown should last as long as the fall animation
  1425. MooshPit[_MP_FALLSTATE] = 1;
  1426. MooshPit[_MP_FALLTIMER] = Max(MOOSHPIT_MIN_FALL_TIME, fall->DeadState+MOOSHPIT_EXTRA_FALL_TIME);
  1427.  
  1428. //Render Link invisible and intangible
  1429. Link->Invisible = true;
  1430. Link->CollDetection = false;
  1431.  
  1432. NoAction();
  1433. }
  1434. else if(MooshPit_OnPit(Link->X, Link->Y, false)==-1&&Link->Action!=LA_FROZEN){ //All other times, while Link is on solid ground, record Link's last position
  1435. if(sideview){
  1436. //Link has no Z value in sideview, so we check if he's on a platform instead
  1437. if(OnSidePlatform(Link->X, Link->Y)){
  1438. MooshPit[_MP_LASTDMAP] = Game->GetCurDMap();
  1439. MooshPit[_MP_LASTSCREEN] = Game->GetCurDMapScreen();
  1440. MooshPit[_MP_LASTX] = Link->X;
  1441. MooshPit[_MP_LASTY] = Link->Y;
  1442. }
  1443. }
  1444. else{
  1445. if(Link->Z<=0){
  1446. MooshPit[_MP_LASTDMAP] = Game->GetCurDMap();
  1447. MooshPit[_MP_LASTSCREEN] = Game->GetCurDMapScreen();
  1448. MooshPit[_MP_LASTX] = Link->X;
  1449. MooshPit[_MP_LASTY] = Link->Y;
  1450. }
  1451. }
  1452. }
  1453. }
  1454. else if(MooshPit[_MP_FALLSTATE]==1){ //Falling animation
  1455. if(MooshPit[_MP_FALLTIMER]>0)
  1456. MooshPit[_MP_FALLTIMER]--;
  1457.  
  1458. if(MOOSHPIT_STUN_ENEMIES_WHILE_FALLING)
  1459. MooshPit_StunEnemies();
  1460.  
  1461. Link->Jump = 0;
  1462. Link->Z = 0;
  1463.  
  1464. //Keep Link invisible just in case
  1465. Link->Invisible = true;
  1466. Link->CollDetection = false;
  1467. NoAction();
  1468. if(MooshPit[_MP_FALLTIMER]==0){
  1469. MooshPit[_MP_SLIDETIMER] = 0;
  1470. if(!isWarp||MooshPit[_MP_DAMAGETYPE]==1){ //If the pit isn't a warp, deal damage and move Link back to the return point
  1471. //If the entry would dump Link back in the pit, dump him out at the failsafe position
  1472. if(MooshPit_OnPit(MooshPit[_MP_ENTRYX], MooshPit[_MP_ENTRYY], false)==15){
  1473. if(MOOSHPIT_NO_REENTER_STAIRS){
  1474. //Call a script to place an FFC under Link to prevent reentering stairs
  1475. int scriptName[] = "MooshPit_StairsFix";
  1476. int ffcNum = RunFFCScript(Game->GetFFCScript(scriptName), 0);
  1477. if(ffcNum>0){
  1478. ffc f = Screen->LoadFFC(ffcNum);
  1479. f->Flags[FFCF_ETHEREAL] = false;
  1480. f->X = MooshPit[_MP_LASTX];
  1481. f->Y = MooshPit[_MP_LASTY];
  1482. }
  1483. }
  1484.  
  1485. Link->X = MooshPit[_MP_LASTX];
  1486. Link->Y = MooshPit[_MP_LASTY];
  1487.  
  1488. //If the failsafe position was on a different screen, warp there
  1489. if(Game->GetCurDMap()!=MooshPit[_MP_LASTDMAP]||Game->GetCurDMapScreen()!=MooshPit[_MP_LASTSCREEN]){
  1490. Link->PitWarp(MooshPit[_MP_LASTDMAP], MooshPit[_MP_LASTSCREEN]);
  1491. }
  1492.  
  1493. Link->Invisible = false;
  1494. Link->CollDetection = true;
  1495. }
  1496. else{
  1497. if(MOOSHPIT_NO_REENTER_STAIRS){
  1498. //Call a script to place an FFC under Link to prevent reentering stairs
  1499. int scriptName[] = "MooshPit_StairsFix";
  1500. int ffcNum = RunFFCScript(Game->GetFFCScript(scriptName), 0);
  1501. if(ffcNum>0){
  1502. ffc f = Screen->LoadFFC(ffcNum);
  1503. f->Flags[FFCF_ETHEREAL] = false;
  1504. f->X = MooshPit[_MP_ENTRYX];
  1505. f->Y = MooshPit[_MP_ENTRYY];
  1506. }
  1507. }
  1508.  
  1509. //Move Link to the entry and make him visible
  1510. Link->X = MooshPit[_MP_ENTRYX];
  1511. Link->Y = MooshPit[_MP_ENTRYY];
  1512.  
  1513. Link->Invisible = false;
  1514. Link->CollDetection = true;
  1515. }
  1516.  
  1517. //Subtract HP based on damage type
  1518. if(MooshPit[_MP_DAMAGETYPE]==1)
  1519. Link->HP -= DAMAGE_FALLLAVA;
  1520. else
  1521. Link->HP -= DAMAGE_FALLHOLE;
  1522. //Play hurt sound and animation
  1523. Link->Action = LA_GOTHURTLAND;
  1524. Link->HitDir = -1;
  1525. Game->PlaySound(SFX_OUCH);
  1526.  
  1527. MooshPit[_MP_FALLSTATE] = 0;
  1528. }
  1529. else{
  1530. MooshPit[_MP_FALLSTATE] = 2;
  1531. MooshPit[_MP_FALLTIMER] = 1;
  1532. ffc warp = Screen->LoadFFC(FFC_MOOSHPIT_AUTOWARPA);
  1533. warp->Data = CMB_MOOSHPIT_AUTOWARPA;
  1534. warp->Flags[FFCF_CARRYOVER] = false;
  1535. }
  1536. }
  1537. }
  1538. else if(MooshPit[_MP_FALLSTATE]==2){ //Just warped
  1539. if(sideview){
  1540. Link->X = MooshPit[_MP_FALLX];
  1541. Link->Y = 0;
  1542. }
  1543. else{
  1544. Link->X = MooshPit[_MP_FALLX];
  1545. Link->Y = MooshPit[_MP_FALLY];
  1546. Link->Z = 176;
  1547. }
  1548. Link->Invisible = false;
  1549. Link->CollDetection = true;
  1550.  
  1551. if(MOOSHPIT_NO_MOVE_WHILE_FALLING){
  1552. MooshPit[_MP_FALLSTATE] = 3;
  1553. NoAction();
  1554. }
  1555. else
  1556. MooshPit[_MP_FALLSTATE] = 0;
  1557. MooshPit[_MP_FALLTIMER] = 0;
  1558. }
  1559. else if(MooshPit[_MP_FALLSTATE]==3){ //Falling into a new room (no action)
  1560. if(MOOSHPIT_STUN_ENEMIES_WHILE_FALLING)
  1561. MooshPit_StunEnemies();
  1562.  
  1563. NoAction();
  1564. if(IsSideview()){
  1565. if(OnSidePlatform(Link->X, Link->Y))
  1566. MooshPit[_MP_FALLSTATE] = 0;
  1567. }
  1568. else{
  1569. if(Link->Z<=0)
  1570. MooshPit[_MP_FALLSTATE] = 0;
  1571. }
  1572. }
  1573. }
  1574. }
  1575.  
  1576. void MooshPit_ResetEntry(){
  1577. MooshPit[_MP_ENTRYX] = Link->X;
  1578. MooshPit[_MP_ENTRYY] = Link->Y;
  1579. MooshPit[_MP_ENTRYDMAP] = Game->GetCurDMap();
  1580. MooshPit[_MP_ENTRYSCREEN] = Game->GetCurDMapScreen();
  1581. }
  1582.  
  1583. const int WATER_CURRENT_FREQ = 5; //# of frames between moving Link (CANNOT BE LOWER THAN 0)
  1584. const int WATER_CURRENT_FLAG = 98; //First of 4 flags to use in the order Up, Down, Left, Right
  1585.  
  1586. void doCurrents (){
  1587. if ( Link->Action==LA_SWIMMING || Link->Action==LA_DIVING ){//If Link is swimming...
  1588.  
  1589. //Move Link based on the current's direction...
  1590. //but make sure it isn't solid
  1591.  
  1592. //Up
  1593. if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG) //If swimming in the appropriate flag
  1594. //And the following combos ahead of Link are not solid
  1595. && !Screen->isSolid(Link->X,Link->Y+6) //NW
  1596. && !Screen->isSolid(Link->X+7,Link->Y+6) //N
  1597. && !Screen->isSolid(Link->X+15,Link->Y+6) //NE
  1598.  
  1599. //Check if the combo below Link is water to prevent getting pushed out
  1600. && waterCheck( ComboAt(Link->X,Link->Y+6))
  1601. && waterCheck( ComboAt(Link->X+7,Link->Y+6))
  1602. && waterCheck( ComboAt(Link->X+15,Link->Y+6))
  1603. )
  1604. Link->Y -= 2;
  1605. //Down
  1606. if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG+1 )
  1607. && !Screen->isSolid(Link->X,Link->Y+17) //SW
  1608. && !Screen->isSolid(Link->X+7,Link->Y+17) //S
  1609. && !Screen->isSolid(Link->X+15,Link->Y+17) //SE
  1610.  
  1611. && waterCheck( ComboAt(Link->X,Link->Y+17))
  1612. && waterCheck( ComboAt(Link->X+7,Link->Y+17))
  1613. && waterCheck( ComboAt(Link->X+15,Link->Y+17))
  1614. )
  1615. Link->Y += 2;
  1616. //Left
  1617. if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG+2 )
  1618. && !Screen->isSolid(Link->X-2,Link->Y+8) //NW
  1619. && !Screen->isSolid(Link->X-2,Link->Y+15) //SW
  1620. )
  1621. Link->X -= 2;
  1622. //Right
  1623. if( ComboFI(Link->X,Link->Y+8, WATER_CURRENT_FLAG+3 )
  1624. && !Screen->isSolid(Link->X+17,Link->Y+8) //NE
  1625. && !Screen->isSolid(Link->X+17,Link->Y+15) //SE
  1626.  
  1627. && waterCheck( ComboAt(Link->X+17,Link->Y+8) )
  1628. && waterCheck( ComboAt(Link->X+17,Link->Y+15) )
  1629. )
  1630. Link->X += 2;
  1631. }
  1632. }
  1633.  
  1634. //Prevents Link from swimming on land
  1635. void swimLandCheck(){
  1636. if( !waterCheck( ComboAt(Link->X,Link->Y+8) ) //If Link is not in the water...
  1637. && ( Link->Action==LA_SWIMMING || Link->Action==LA_DIVING ) ) //and swimming...
  1638. Link->Action = LA_NONE; //Make him stop swimming
  1639. }
  1640.  
  1641. //Checks if the designated combo is any water type
  1642. bool waterCheck(int cmb){
  1643. if( Screen->ComboT[cmb] == CT_WATER
  1644. || Screen->ComboT[cmb] == CT_SWIMWARP
  1645. || Screen->ComboT[cmb] == CT_SWIMWARPB
  1646. || Screen->ComboT[cmb] == CT_SWIMWARPC
  1647. || Screen->ComboT[cmb] == CT_SWIMWARPD
  1648. || Screen->ComboT[cmb] == CT_DIVEWARP
  1649. || Screen->ComboT[cmb] == CT_DIVEWARPB
  1650. || Screen->ComboT[cmb] == CT_DIVEWARPC
  1651. || Screen->ComboT[cmb] == CT_DIVEWARPD
  1652. )
  1653. return true; //The combo is water
  1654. return false;
  1655. }
  1656.  
  1657. // This enables FFCs to be solid without having to lay a solid combo under it.
  1658. //
  1659. void GB_SolidifyFFC(ffc this){
  1660. int tho=(this->EffectHeight-16);
  1661. int two=(this->EffectWidth-16);
  1662. int onscreenedge;
  1663.  
  1664. //This detects if link is on the edge of the screen
  1665. if(Link->X<8 || Link->Y<8 || Link->X>232 || Link->Y>152){
  1666. onscreenedge=1;
  1667. }
  1668. else{
  1669. onscreenedge=0;
  1670. }
  1671.  
  1672. //This checks if you're above or below the NPC to create an overhead effect
  1673. if(Link->Y<this->Y-8+tho && onscreenedge==0){
  1674. this->Flags[FFCF_OVERLAY] = true;
  1675. }
  1676. else{
  1677. this->Flags[FFCF_OVERLAY] = false;
  1678. }
  1679.  
  1680. if((Abs(Link->X - this->X-two) < 10) && (Link->Y <= this->Y+tho + 12) && (Link->Y > this->Y+tho+8)){
  1681. Link->Y = this->Y+tho+12;
  1682. }
  1683. if((Abs(Link->Y - this->Y-tho) < 10) && (Link->X >= this->X - 12) && (Link->X < this->X+two-8)){
  1684. Link->X = this->X-12;
  1685. }
  1686. if((Abs(Link->X - this->X-two) < 10) && (Link->Y >= this->Y+tho - 12) && (Link->Y < this->Y+tho-8)){
  1687. Link->Y = this->Y+tho-12;
  1688. }
  1689. if((Abs(Link->Y - this->Y-tho) < 10) && (Link->X <= this->X+two + 12) && (Link->X > this->X+two+8)){
  1690. Link->X = this->X+two+12;
  1691. }
  1692. }
  1693.  
  1694.  
  1695. const int COMBOFX_NOT_TRIGGERED_BY_PUSH = 1; //Set to 1 if you don't want push blocks triggering slash effects (like with a pushable pot)
  1696.  
  1697. const int NPC_COMBOSFX_DROPSET = 85; //Item dropset enemy (Fire by default)
  1698. const int COMBOSFX_CHECKALL = 1; //If set to 1, the script will check all combos on screen every frame. This is generally slower and not advised, but there may be cases you'd want this.
  1699.  
  1700. void CSA_AutoSlashable_Update(int lastDMapScreen){
  1701. if(lastDMapScreen[0]!=Game->GetCurDMap()||lastDMapScreen[1]!=Game->GetCurDMapScreen()){
  1702. int i; int j; int k;
  1703.  
  1704. int autoSlashableID[65280];
  1705. int autoSlashableData[2056];
  1706. autoSlashableData[0] = 0;
  1707.  
  1708. //AUTO SLASHABLES HERE
  1709. //Add your auto slashables with the provided function here
  1710. // COMBO SFX TYPE GFX CS FRAMES ASPEED RAND/DROPSET
  1711. //EXAMPLE:
  1712. //CSA_AddAutoSlashable(autoSlashableID, autoSlashableData, 7680, 41, 2, 52020, 2, 0, 0, 0); //Bush - Green
  1713.  
  1714.  
  1715.  
  1716. //End of auto slashables
  1717.  
  1718. for(i=0; i<176; i++){
  1719. int cd = Screen->ComboD[i];
  1720. if(autoSlashableID[cd]){
  1721. int scr[] = "ComboSFXAnim";
  1722. int args[8];
  1723. k = autoSlashableID[cd];
  1724. for(j=0; j<8; j++){
  1725. args[j] = autoSlashableData[k*8+j];
  1726. }
  1727.  
  1728. RunFFCScript(Game->GetFFCScript(scr), args);
  1729.  
  1730. autoSlashableID[cd] = 0;
  1731. }
  1732. }
  1733.  
  1734. lastDMapScreen[0] = Game->GetCurDMap();
  1735. lastDMapScreen[1] = Game->GetCurDMapScreen();
  1736. }
  1737. }
  1738.  
  1739. ffc script ComboSFXAnim{
  1740. void run(int combo, int sfx, int type, int gfx, int cs, int frames, int aspeed, int rand_or_dropset){
  1741. int i; int j; int k;
  1742. int comboCount; //Max index of positions[]
  1743. int positions[176]; //Keeps track of all combo position (0-175) currently being tracked
  1744. int lastCombo[176]; //Last known combo of every position onscreen
  1745. bool hadCombo[176]; //Used for when COMBOSFX_CHECKALL is used in combination with negative combo ID
  1746.  
  1747. //Negative combo ID makes it animate every time the combo changes
  1748. bool everyFrame = false;
  1749. if(combo<0){
  1750. combo = Abs(combo);
  1751. everyFrame = true;
  1752. }
  1753.  
  1754. for(i=0; i<176; i++){
  1755. positions[i] = -1;
  1756. lastCombo[i] = Screen->ComboD[i];
  1757. }
  1758. //Find all valid combos
  1759. for(i=0; i<176; i++){
  1760. if(Screen->ComboD[i]==combo||COMBOSFX_CHECKALL){
  1761. positions[comboCount] = i;
  1762. if(Screen->ComboD[i]==combo)
  1763. hadCombo[i] = true;
  1764. comboCount++;
  1765. }
  1766. }
  1767.  
  1768. int lastMovingBlockX;
  1769. int lastMovingBlockY;
  1770. int movingBlockPositionIndex = -1; //Array index for the moving block's combo position
  1771.  
  1772. while(true){
  1773. bool blockStartedMoving = false;
  1774. bool blockStoppedMoving = false;
  1775. //If the push block is active
  1776. if(Screen->MovingBlockX>-1&&Screen->MovingBlockY>-1){
  1777. //If this is the first frame it was active
  1778. if(lastMovingBlockX==-1){
  1779. blockStartedMoving = true;
  1780. }
  1781. }
  1782. //If the push block was previously active
  1783. if(lastMovingBlockX>-1&&lastMovingBlockY>-1){
  1784. //If it isn't active anymore
  1785. if(Screen->MovingBlockX==-1){
  1786. blockStoppedMoving = true;
  1787. }
  1788. }
  1789.  
  1790. //Only check combos that had the right ID on init
  1791. for(i=0; i<comboCount; i++){
  1792. j = positions[i];
  1793. if(j>-1){
  1794. //Whenever it changes
  1795. if(Screen->ComboD[j]!=lastCombo[j]){
  1796. //Keeps track of whether a push block triggered the combo change
  1797. bool wasPushBlockTriggered;
  1798. if(COMBOFX_NOT_TRIGGERED_BY_PUSH){
  1799. if(blockStartedMoving){
  1800. //If the push block was triggered by this combo
  1801. if(ComboAt(Screen->MovingBlockX+8, Screen->MovingBlockY+8)==j){
  1802. wasPushBlockTriggered = true;
  1803. }
  1804. }
  1805. if(blockStoppedMoving){
  1806. //If the push block ended up on this combo
  1807. if(ComboAt(lastMovingBlockX+8, lastMovingBlockY+8)==j){
  1808. wasPushBlockTriggered = true;
  1809. }
  1810. }
  1811. }
  1812.  
  1813. if(Screen->ComboD[j]==combo)
  1814. hadCombo[j] = true;
  1815. //Do the animation if other conditions are right
  1816. bool doAnim = false;
  1817. if(!everyFrame){
  1818. if(lastCombo[j]==combo)
  1819. doAnim = true;
  1820. }
  1821. else{
  1822. if(hadCombo[j])
  1823. doAnim = true;
  1824. }
  1825.  
  1826. if(wasPushBlockTriggered)
  1827. doAnim = false;
  1828.  
  1829. if(doAnim){
  1830. Game->PlaySound(sfx);
  1831. //Create and kill an enemy if the dropset is set
  1832. if(rand_or_dropset<0){
  1833. npc n = CreateNPCAt(NPC_COMBOSFX_DROPSET, ComboX(j), ComboY(j));
  1834. n->ItemSet = Abs(rand_or_dropset);
  1835. n->HP = -1000;
  1836. n->DrawYOffset = -1000;
  1837. }
  1838. if(type>1){ //Particle animations
  1839. int scr[] = "CSA_Animations";
  1840. int args[8];
  1841. args[0] = type-2;
  1842. args[1] = gfx;
  1843. args[2] = cs;
  1844. args[3] = frames;
  1845. args[4] = aspeed;
  1846. args[5] = rand_or_dropset;
  1847. ffc f = Screen->LoadFFC(RunFFCScript(Game->GetFFCScript(scr), args));
  1848. f->X = ComboX(j);
  1849. f->Y = ComboY(j);
  1850. }
  1851. else if(type==1){ //Sprite animation
  1852. lweapon poof = CreateLWeaponAt(LW_SCRIPT10, ComboX(j), ComboY(j));
  1853. poof->UseSprite(gfx);
  1854. poof->DrawYOffset = 0;
  1855. if(cs>0)
  1856. poof->CSet = cs;
  1857. poof->DeadState = poof->NumFrames*poof->ASpeed;
  1858. if(rand_or_dropset>1){
  1859. poof->OriginalTile += Rand(rand_or_dropset)*poof->NumFrames;
  1860. poof->Tile = poof->OriginalTile;
  1861. }
  1862. }
  1863. }
  1864. lastCombo[j] = Screen->ComboD[j];
  1865. }
  1866. }
  1867. }
  1868.  
  1869. if(blockStartedMoving){
  1870. //Find if the moving block is starting on one of the combo positions in the array
  1871. k = ComboAt(Screen->MovingBlockX+8, Screen->MovingBlockY+8);
  1872. for(i=0; i<comboCount; i++){
  1873. j = positions[i];
  1874. if(j==k){
  1875. movingBlockPositionIndex = i;
  1876. break;
  1877. }
  1878. }
  1879. }
  1880. else if(blockStoppedMoving){
  1881. //If the moving block was in the array, update its position
  1882. if(movingBlockPositionIndex>-1){
  1883. k = ComboAt(lastMovingBlockX+8, lastMovingBlockY+8);
  1884. positions[movingBlockPositionIndex] = k;
  1885. }
  1886. movingBlockPositionIndex = -1;
  1887. }
  1888.  
  1889. lastMovingBlockX = Screen->MovingBlockX;
  1890. lastMovingBlockY = Screen->MovingBlockY;
  1891. Waitframe();
  1892. }
  1893. }
  1894. }
  1895.  
  1896. ffc script CSA_Animations{
  1897. void run(int type, int gfx, int cs, int frames, int aspeed, int rand_or_dropset){
  1898. this->Flags[FFCF_ETHEREAL] = true;
  1899. int i; int j; int k;
  1900. int thisNum;
  1901. for(i=1; i<=32; i++){
  1902. ffc f = Screen->LoadFFC(i);
  1903. if(f->Script==this->Script){
  1904. if(f==this)
  1905. break;
  1906. else
  1907. thisNum++;
  1908. }
  1909. }
  1910.  
  1911.  
  1912. if(type==0){ //Bush leaves
  1913. for(i=0; i<8; i++){
  1914. for(j=0; j<3; j++){
  1915. TileAnim_BushAnim(this->X-8, this->Y, gfx, cs, i, thisNum);
  1916. Waitframe();
  1917. }
  1918. }
  1919. }
  1920. else{
  1921. int particleX[32];
  1922. int particleY[32];
  1923. int particleTile[32];
  1924. int particleA[32];
  1925. int particleS[32];
  1926. int particleT[32];
  1927. int particleMT[32];
  1928. int particleAnim[32];
  1929. int particle[16] = {999, particleX, particleY, particleTile, particleA, particleS, particleT, particleMT, particleAnim};
  1930. if(type==1){ //Random spread
  1931. for(i=0; i<12; i++){
  1932. j = gfx;
  1933. if(rand_or_dropset>1)
  1934. j += Rand(rand_or_dropset)*Max(frames, 1);
  1935. Particle_Add(particle, this->X+Rand(-4, 4), this->Y+Rand(-4, 4), j, Rand(360), Rand(20, 120)/100, Rand(12, 18));
  1936. }
  1937. //Run until all particles are dead
  1938. while(particle[0]>0){
  1939. Particle_Update(particle, frames, aspeed, cs);
  1940. Waitframe();
  1941. }
  1942. }
  1943. else if(type==2){ //Aimed spread
  1944. k = Angle(Link->X, Link->Y, this->X, this->Y);
  1945. for(i=0; i<6; i++){
  1946. j = gfx;
  1947. if(rand_or_dropset>1)
  1948. j += Rand(rand_or_dropset)*Max(frames, 1);
  1949. Particle_Add(particle, this->X+Rand(-4, 4), this->Y+Rand(-4, 4), j, k+Rand(-20, 20), Rand(5, 20)/10, Rand(12, 18));
  1950. }
  1951. //Run until all particles are dead
  1952. while(particle[0]>0){
  1953. Particle_Update(particle, frames, aspeed, cs);
  1954. Waitframe();
  1955. }
  1956. }
  1957. }
  1958. }
  1959. void Particle_Update(int particle, int frames, int aspeed, int cs){
  1960. int particleX = particle[1];
  1961. int particleY = particle[2];
  1962. int particleTile = particle[3];
  1963. int particleA = particle[4];
  1964. int particleS = particle[5];
  1965. int particleT = particle[6];
  1966. int particleMT = particle[7];
  1967. int particleAnim = particle[8];
  1968. particle[0] = 0; //Reset particle counter for the frame
  1969. for(int i=0; i<32; i++){
  1970. if(particleT[i]>0){
  1971. particle[0]++;
  1972.  
  1973. //Movement
  1974. particleX[i] += VectorX(particleS[i], particleA[i]);
  1975. particleY[i] += VectorY(particleS[i], particleA[i]);
  1976.  
  1977. //Animations
  1978. int til = particleTile[i];
  1979. if(frames>0){
  1980. if(aspeed==0){
  1981. int j = Floor((particleMT[i]-particleT[i])/(particleMT[i]/frames));
  1982. til = particleTile[i]+Clamp(j, 0, frames-1);
  1983. }
  1984. else{
  1985. til = particleTile[i] + Floor(particleAnim[i]/aspeed);
  1986. particleAnim[i] = (particleAnim[i]+1)%(frames*aspeed);
  1987. }
  1988. }
  1989.  
  1990. //Drawing
  1991. Screen->FastTile(4, particleX[i], particleY[i], til, cs, 128);
  1992. particleT[i]--;
  1993. }
  1994. }
  1995. }
  1996. int Particle_Add(int particle, int x, int y, int tile, int angle, int step, int time){
  1997. int particleX = particle[1];
  1998. int particleY = particle[2];
  1999. int particleTile = particle[3];
  2000. int particleA = particle[4];
  2001. int particleS = particle[5];
  2002. int particleT = particle[6];
  2003. int particleMT = particle[7];
  2004. int particleAnim = particle[8];
  2005. for(int i=0; i<32; i++){
  2006. //Find unused particle, set the stuff
  2007. if(particleT[i]==0){
  2008. particleX[i] = x;
  2009. particleY[i] = y;
  2010. particleTile[i] = tile;
  2011. particleA[i] = angle;
  2012. particleS[i] = step;
  2013. particleT[i] = time;
  2014. particleMT[i] = time;
  2015. particleAnim[i] = 0;
  2016. return i;
  2017. }
  2018. }
  2019. }
  2020. void TileAnim_BushAnim(int x, int y, int tile, int cset, int frame, int thisNum){
  2021. int posX[32] = {16, 6, 20, 14, //Frame 1
  2022. 16, 9, 17, 14, //Frame 2
  2023. 17, 10, 14, 12, //Frame 3
  2024. 17, 11, 15, 11, //Frame 4
  2025. 19, 8, 18, 10, //Frame 5
  2026. 20, 4, 19, 9, //Frame 6
  2027. 21, 3, 22, 8, //Frame 7
  2028. 14, 1, 16, 7}; //Frame 8
  2029.  
  2030.  
  2031. int posY[32] = {11, 8, 7, 1, //Frame 1
  2032. 14, 9, 8, -1, //Frame 2
  2033. 16, 10, 10, -2, //Frame 3
  2034. 18, 10, 10, -3, //Frame 4
  2035. 20, 10, 14, -4, //Frame 5
  2036. 21, 10, 14, -6, //Frame 6
  2037. 23, 9, 14, -9, //Frame 7
  2038. 24, 7, 21, -11};//Frame 8
  2039.  
  2040. int flip[32] = {0, 0, 1, 0, //Frame 1
  2041. 0, 0, 1, 0, //Frame 2
  2042. 1, 0, 1, 0, //Frame 3
  2043. 0, 1, 0, 3, //Frame 4
  2044. 0, 1, 0, 0, //Frame 5
  2045. 0, 0, 0, 0, //Frame 6
  2046. 0, 0, 1, 0, //Frame 7
  2047. 1, 1, 0, 0}; //Frame 8
  2048.  
  2049. for(int i=0; i<4; i++){
  2050. Screen->DrawTile(4, x+posX[frame*4+i]-4, y+posY[frame*4+i]-4, tile+i, 1, 1, cset, -1, -1, 0, 0, 0, flip[frame*4+i], true, 128);
  2051. }
  2052. }
  2053. }
  2054.  
  2055. void CSA_AddAutoSlashable(int autoSlashableID, int autoSlashableData, int combo, int sfx, int type, int gfx, int cs, int frames, int aspeed, int rand_or_dropset){
  2056. ++autoSlashableData[0];
  2057. int k = autoSlashableData[0];
  2058.  
  2059. autoSlashableID[combo] = k;
  2060.  
  2061. autoSlashableData[k*8+0] = combo;
  2062. autoSlashableData[k*8+1] = sfx;
  2063. autoSlashableData[k*8+2] = type;
  2064. autoSlashableData[k*8+3] = gfx;
  2065. autoSlashableData[k*8+4] = cs;
  2066. autoSlashableData[k*8+5] = frames;
  2067. autoSlashableData[k*8+6] = aspeed;
  2068. autoSlashableData[k*8+7] = rand_or_dropset;
  2069.  
  2070. autoSlashableData[0] = Min(autoSlashableData[0], 256);
  2071. }
  2072.  
  2073.  
  2074. const int dayLength = 5; //Length of a day or night in minutes;
  2075. const int I_NIGHT = 45; //An unused item ID, placed into Link's inventory or removed to change day/night
  2076. const int dayDMAP0 = 0; //Daytime DMap #0
  2077. const int nightDMAP0 = 1; //Night DMap #0
  2078. const int dayDMAP1 = -1; //Daytime DMap #1
  2079. const int nightDMAP1 = -1; //Night DMap #1
  2080.  
  2081. const int dayDMAP24 = 24; //Daytime DMap #2
  2082. const int nightDMAP24 = 25; //Night DMap #2
  2083. const int dayDMAP25 = -25; //Daytime DMap #3
  2084. const int nightDMAP25 = -25; //Night DMap #3
  2085.  
  2086. const int dayDMAP11 = 11; //Daytime DMap #4
  2087. const int nightDMAP11 = 12; //Night DMap #4
  2088. const int dayDMAP12 = -12; //Daytime DMap #5
  2089. const int nightDMAP12 = -12; //Night DMap #5
  2090.  
  2091. const int dayDMAP13 = 13; //Daytime DMap #6
  2092. const int nightDMAP13 = 14; //Night DMap #6
  2093. const int dayDMAP14 = -14; //Daytime DMap #7
  2094. const int nightDMAP14 = -14; //Night DMap #7
  2095.  
  2096. const int dayDMAP26 = 26; //Daytime DMap #6
  2097. const int nightDMAP26 = 27; //Night DMap #6
  2098. const int dayDMAP27 = -27; //Daytime DMap #7
  2099. const int nightDMAP27 = -27; //Night DMap #7
  2100.  
  2101. global script FairyQSTglobal
  2102.  
  2103. {void changeNight(bool cycle)
  2104. {if(cycle){
  2105. if(Link->Item[I_NIGHT])Link->Item[I_NIGHT]=false;
  2106. else{Link->Item[I_NIGHT]=true;}
  2107. }if(Game->GetCurScreen()!=128){
  2108. if(dayDMAP0>=0&&nightDMAP0>=0){
  2109. if(Game->GetCurDMap()==dayDMAP0 && Link->Item[I_NIGHT]){
  2110. Link->PitWarp(nightDMAP0, Game->GetCurScreen());
  2111. } else if(Game->GetCurDMap()==nightDMAP0 && !Link->Item[I_NIGHT]){
  2112. Link->PitWarp(dayDMAP0, Game->GetCurScreen());
  2113. }
  2114. }
  2115. if(dayDMAP1>=0&&nightDMAP1>=0){
  2116. if(Game->GetCurDMap()==dayDMAP1 && Link->Item[I_NIGHT]){
  2117. Link->PitWarp(nightDMAP1, Game->GetCurScreen());
  2118. } else if(Game->GetCurDMap()==nightDMAP1 && !Link->Item[I_NIGHT]){
  2119. Link->PitWarp(dayDMAP1, Game->GetCurScreen());
  2120. }
  2121. }
  2122. if(dayDMAP24>=24&&nightDMAP24>=24){
  2123. if(Game->GetCurDMap()==dayDMAP24 && Link->Item[I_NIGHT]){
  2124. Link->PitWarp(nightDMAP24, Game->GetCurScreen());
  2125. } else if(Game->GetCurDMap()==nightDMAP24 && !Link->Item[I_NIGHT]){
  2126. Link->PitWarp(dayDMAP24, Game->GetCurScreen());
  2127. }
  2128. }
  2129. if(dayDMAP25>=24&&nightDMAP25>=24){
  2130. if(Game->GetCurDMap()==dayDMAP25 && Link->Item[I_NIGHT]){
  2131. Link->PitWarp(nightDMAP25, Game->GetCurScreen());
  2132. } else if(Game->GetCurDMap()==nightDMAP25 && !Link->Item[I_NIGHT]){
  2133. Link->PitWarp(dayDMAP25, Game->GetCurScreen());
  2134. }
  2135. }
  2136. if(dayDMAP11>=11&&nightDMAP11>=11){
  2137. if(Game->GetCurDMap()==dayDMAP11 && Link->Item[I_NIGHT]){
  2138. Link->PitWarp(nightDMAP11, Game->GetCurScreen());
  2139. } else if(Game->GetCurDMap()==nightDMAP11 && !Link->Item[I_NIGHT]){
  2140. Link->PitWarp(dayDMAP11, Game->GetCurScreen());
  2141. }
  2142. }
  2143. if(dayDMAP12>=11&&nightDMAP12>=11){
  2144. if(Game->GetCurDMap()==dayDMAP12 && Link->Item[I_NIGHT]){
  2145. Link->PitWarp(nightDMAP12, Game->GetCurScreen());
  2146. } else if(Game->GetCurDMap()==nightDMAP12 && !Link->Item[I_NIGHT]){
  2147. Link->PitWarp(dayDMAP12, Game->GetCurScreen());
  2148. }
  2149. }
  2150. if(dayDMAP13>=13&&nightDMAP13>=13){
  2151. if(Game->GetCurDMap()==dayDMAP13 && Link->Item[I_NIGHT]){
  2152. Link->PitWarp(nightDMAP13, Game->GetCurScreen());
  2153. } else if(Game->GetCurDMap()==nightDMAP13 && !Link->Item[I_NIGHT]){
  2154. Link->PitWarp(dayDMAP13, Game->GetCurScreen());
  2155. }
  2156. }
  2157. if(dayDMAP14>=13&&nightDMAP14>=13){
  2158. if(Game->GetCurDMap()==dayDMAP14 && Link->Item[I_NIGHT]){
  2159. Link->PitWarp(nightDMAP14, Game->GetCurScreen());
  2160. } else if(Game->GetCurDMap()==nightDMAP14 && !Link->Item[I_NIGHT]){
  2161. Link->PitWarp(dayDMAP14, Game->GetCurScreen());
  2162. }
  2163. }
  2164. if(dayDMAP26>=26&&nightDMAP26>=26){
  2165. if(Game->GetCurDMap()==dayDMAP26 && Link->Item[I_NIGHT]){
  2166. Link->PitWarp(nightDMAP26, Game->GetCurScreen());
  2167. } else if(Game->GetCurDMap()==nightDMAP26 && !Link->Item[I_NIGHT]){
  2168. Link->PitWarp(dayDMAP26, Game->GetCurScreen());
  2169. }
  2170. }
  2171. if(dayDMAP27>=26&&nightDMAP27>=26){
  2172. if(Game->GetCurDMap()==dayDMAP27 && Link->Item[I_NIGHT]){
  2173. Link->PitWarp(nightDMAP27, Game->GetCurScreen());
  2174. } else if(Game->GetCurDMap()==nightDMAP27 && !Link->Item[I_NIGHT]){
  2175. Link->PitWarp(dayDMAP27, Game->GetCurScreen());
  2176. }
  2177. }// You can copy this entire IF statement and change it to, say, dayDMAP10 and nightDMAP11 to create an
  2178. // additional DMap to have a day/night cycle for. This can be done indefinitely.
  2179.  
  2180. }
  2181. }
  2182.  
  2183. void run(){
  2184. int frame = 0;
  2185. int min = 0;
  2186. MooshPit_Init();
  2187. int waterCounter = 0;
  2188. int lastDMapScreen[2];
  2189. while(true){
  2190. MooshPit_Update();
  2191. bool cycle = false;
  2192. if(min==dayLength){cycle=true;min=0;}
  2193. changeNight(cycle);
  2194. Waitdraw();
  2195. frame++;
  2196. if(frame==3600){
  2197. frame=0;
  2198. min++;
  2199. if ( waterCounter >= WATER_CURRENT_FREQ )
  2200. {
  2201. doCurrents();
  2202. waterCounter = 0;
  2203. }
  2204. waterCounter++;
  2205. swimLandCheck();
  2206. }
  2207. CSA_AutoSlashable_Update(lastDMapScreen);
  2208. Waitdraw();
  2209. Waitframe();
  2210. }
  2211. }
  2212. }
  2213.  
  2214. ffc script MooshPit_StairsFix{
  2215. void run(){
  2216. this->Flags[FFCF_ETHEREAL] = false;
  2217. while(LinkCollision(this)){
  2218. Waitframe();
  2219. }
  2220. this->X = 0;
  2221. this->Y = 0;
  2222. this->Data = 0;
  2223. }
  2224. }
  2225.  
  2226.  
  2227. ffc script flowingWater{
  2228. void run ( int frequency ){
  2229. if( frequency < 1 )
  2230. frequency = WATER_CURRENT_FREQ;
  2231. while ( true ){
  2232. doCurrents();
  2233. Waitframes(frequency);
  2234. swimLandCheck();
  2235. }
  2236. }
  2237. }
  2238.  
  2239.  
  2240. lweapon script scr9
  2241. {
  2242. void run()
  2243. {
  2244. TraceS("Running Weapon Script scr9"); TraceNL();
  2245. int clk = 200;
  2246. this->X = 50; this->Y = 50;
  2247.  
  2248. while(1)
  2249. {
  2250. //++this->ScriptTile;
  2251. if ( Input->ReadKey[KEY_P] )
  2252. {
  2253. this->DeadState = WDS_DEAD;
  2254. Trace(this->DeadState);
  2255.  
  2256. }
  2257.  
  2258. Waitframe();
  2259. }
  2260. }
  2261. }
  2262.  
  2263. npc script n
  2264. {
  2265. void run()
  2266. {
  2267. while(this->isValid())
  2268. {
  2269. //TraceS("NPC Script N is Running"); TraceNL();
  2270. //TraceS("CanMove returned: "); TraceB(this->CanMove({this->Dir,4,0}));
  2271. bool can = this->CanMove({this->Dir});
  2272. if ( !can ) { TraceS("CanMove returned false."); TraceNL(); }
  2273. if ( Input->ReadKey[KEY_N] ) this->Attack();
  2274. if ( Input->ReadKey[KEY_K] ) this->Remove();
  2275. if ( Input->ReadKey[KEY_L] ) this->Slide();
  2276. Waitframe();
  2277. }
  2278. }
  2279. }
  2280.  
  2281. npc script floater_old
  2282. {
  2283. void run()
  2284. {
  2285. TraceS("Running npc script 'test'"); TraceNL();
  2286. this->Dir = Rand(0,3);
  2287. while(this->isValid())
  2288. {
  2289.  
  2290.  
  2291. this->FloatingWalk({10,200,2});
  2292. Waitframe();
  2293. }
  2294. }
  2295. }
  2296.  
  2297. npc script floater
  2298. {
  2299. void run()
  2300. {
  2301. int attack_clk;
  2302. TraceS("Running npc script 'test'"); TraceNL();
  2303. this->Dir = Rand(0,3);
  2304. switch(this->Dir)
  2305. {
  2306. case DIR_UP: this->ScriptTile = 862; break;
  2307. case DIR_DOWN: this->ScriptTile = 861; break;
  2308. case DIR_LEFT: this->ScriptTile = 882; break;
  2309. case DIR_RIGHT: this->ScriptTile = 881; break;
  2310. default: break;
  2311. }
  2312.  
  2313. this->ScriptTile = this->Tile;
  2314. while(this->isValid())
  2315. {
  2316. switch(this->Dir)
  2317. {
  2318. case DIR_UP: this->ScriptTile = 862; break;
  2319. case DIR_DOWN: this->ScriptTile = 861; break;
  2320. case DIR_LEFT: this->ScriptTile = 882; break;
  2321. case DIR_RIGHT: this->ScriptTile = 881; break;
  2322. default: break;
  2323. }
  2324. //this->ScriptTile;
  2325. //if ( this->CanMove(this->Dir) )
  2326. //{
  2327. this->FloatingWalk({10,200,2});
  2328. //}
  2329. if ( this->LinedUp(200,true) )
  2330. {
  2331. if ( this->LinkInRange(100) )
  2332. {
  2333. if (!attack_clk)
  2334. {
  2335. attack_clk = 100;
  2336. this->Attack();
  2337. }
  2338. }
  2339. }
  2340. if (attack_clk) --attack_clk;
  2341. Waitframe();
  2342. }
  2343. }
  2344. }
  2345.  
  2346. npc script walker
  2347. {
  2348. void run()
  2349. {
  2350. int attack_clk;
  2351. TraceS("Running npc script 'test'"); TraceNL();
  2352. this->Dir = Rand(0,3);
  2353. switch(this->Dir)
  2354. {
  2355. case DIR_UP: this->ScriptTile = 862; break;
  2356. case DIR_DOWN: this->ScriptTile = 861; break;
  2357. case DIR_LEFT: this->ScriptTile = 882; break;
  2358. case DIR_RIGHT: this->ScriptTile = 881; break;
  2359. default: break;
  2360. }
  2361.  
  2362. this->ScriptTile = this->Tile;
  2363. while(this->isValid())
  2364. {
  2365. switch(this->Dir)
  2366. {
  2367. case DIR_UP: this->ScriptTile = 862; break;
  2368. case DIR_DOWN: this->ScriptTile = 861; break;
  2369. case DIR_LEFT: this->ScriptTile = 882; break;
  2370. case DIR_RIGHT: this->ScriptTile = 881; break;
  2371. default: break;
  2372. }
  2373. //this->ScriptTile;
  2374. //if ( this->CanMove(this->Dir) )
  2375. //{
  2376. this->HaltingWalk({10,1,0,50,2});
  2377. //}
  2378. if ( this->LinedUp(200,true) )
  2379. {
  2380. if ( this->LinkInRange(100) )
  2381. {
  2382. if (!attack_clk)
  2383. {
  2384. attack_clk = 100;
  2385. this->Attack();
  2386. }
  2387. }
  2388. }
  2389. if (attack_clk) --attack_clk;
  2390. Waitframe();
  2391. }
  2392. }
  2393. }
  2394.  
  2395.  
  2396. ffc script Only_Move_With_Secrets{
  2397. void run(int initial_x, int initial_y){
  2398. initial_x = this->Vx;
  2399. initial_y = this->Vy;
  2400. this->Vx = 0;
  2401. this->Vy = 0;
  2402. while (!Screen->State[ST_SECRET]) Waitframe();
  2403. this->Vx = initial_x;
  2404. this->Vy = initial_y;
  2405. }
  2406. }
  2407.  
  2408. ffc script CaveItemRoomWarp
  2409. {
  2410. untyped cachedData[NUM_CACHED_DATA] = {-1, -1};
  2411. enum cachedIndex
  2412. {
  2413. CACHED_COMBO,
  2414. CACHED_SPECIALITEM_SCRIPT,
  2415. NUM_CACHED_DATA
  2416. };
  2417. define CARRY_ONLY_SPECIALITEM = NOCARRY_B_SECRET | NOCARRY_B_ITEM | NOCARRY_B_LOCKBLOCK | NOCARRY_B_BOSSLOCKBLOCK | NOCARRY_B_CHEST | NOCARRY_B_LOCKEDCHEST | NOCARRY_B_BOSSCHEST;
  2418. /**
  2419. * SETUP:
  2420. * Set the combo for this FFC to any tile warping combo
  2421. * - example: Stair [A], Cave (Walk Down) [A]
  2422. * - if it is set to anything else, the lowest-numbered valid 'Stairs[A]' combo will be used.
  2423. * Set the tile warp on the screen to the destination you desire.
  2424. * - Also set the warp type, return square, etc; do not use 'Cave/Item Cellar'
  2425. * On the destination screen, both sidewarp A and tilewarp A will be set to return to the origin.
  2426. * -Set these warps for any sides/tiles you want to return you.
  2427. * -They will automatically use the same warp type you warped with as well
  2428. * -The return warps will send you to the same-letter return square that you set for the warp
  2429. *
  2430. * Extra (optional) features:
  2431. * - ITEM: If d0 is an item ID, then it will place that item on the target screen, tied to the SOURCE screen's `ST_SPECIALITEM` state.
  2432. * -To disable this, use a negative number.
  2433. * -You cannot use this and also use screen state carryover on the target screen.
  2434. * -You cannot use this and also use a screen script on the target screen, unless it is the SpawnSpecialItem script.
  2435. * -To position the item placement, set up the SpawnSpecialItem script on the target screen (ignoring it's itemID parameter)
  2436. *
  2437. */
  2438. void run(int itemid)
  2439. {
  2440. combodata cd = Game->LoadComboData(this->Data);
  2441. int tilewarp;
  2442. switch(cd->Type) //start What Tilewarp?
  2443. {
  2444. case CT_CAVE:
  2445. case CT_CAVE2:
  2446. case CT_DIVEWARP:
  2447. case CT_PIT:
  2448. case CT_STAIR:
  2449. case CT_SWIMWARP:
  2450. tilewarp = TILEWARP_A;
  2451. break;
  2452.  
  2453. case CT_CAVEB:
  2454. case CT_CAVE2B:
  2455. case CT_DIVEWARPB:
  2456. case CT_PITB:
  2457. case CT_STAIRB:
  2458. case CT_SWIMWARPB:
  2459. tilewarp = TILEWARP_B;
  2460. break;
  2461.  
  2462. case CT_CAVEC:
  2463. case CT_CAVE2C:
  2464. case CT_DIVEWARPC:
  2465. case CT_PITC:
  2466. case CT_STAIRC:
  2467. case CT_SWIMWARPC:
  2468. tilewarp = TILEWARP_C;
  2469. break;
  2470.  
  2471. case CT_CAVED:
  2472. case CT_CAVE2D:
  2473. case CT_DIVEWARPD:
  2474. case CT_PITD:
  2475. case CT_STAIRD:
  2476. case CT_SWIMWARPD:
  2477. tilewarp = TILEWARP_D;
  2478. break;
  2479.  
  2480. default:
  2481. {
  2482. tilewarp = TILEWARP_A;
  2483. if(cachedData[CACHED_COMBO]>-1)
  2484. {
  2485. this->Data = cachedData[CACHED_COMBO];
  2486. break;
  2487. }
  2488. combodata cd;
  2489. for(int q = 1; q < MAX_COMBOS; ++q)
  2490. {
  2491. cd = Game->LoadComboData(q);
  2492. if(cd->Type == CT_STAIR)
  2493. {
  2494. cachedData[CACHED_COMBO] = q;
  2495. break;
  2496. }
  2497. }
  2498. unless(cachedData[CACHED_COMBO]>-1) //No stairs combos in the ENTIRE COMBOLIST?
  2499. {
  2500. cd->Type = CT_STAIR;
  2501. cachedData[CACHED_COMBO] = cd->ID;
  2502. }
  2503. this->Data = cachedData[CACHED_COMBO];
  2504. }
  2505. } //end
  2506.  
  2507. unless(cachedData[CACHED_SPECIALITEM_SCRIPT]>-1)
  2508. {
  2509. cachedData[CACHED_SPECIALITEM_SCRIPT] = Game->GetScreenScript("SpawnSpecialItem");
  2510. }
  2511.  
  2512. int dmapID = Screen->GetTileWarpDMap(tilewarp);
  2513. dmapdata destDMap = Game->LoadDMapData(dmapID);
  2514. mapdata md = Game->LoadMapData(destDMap->Map, DMapToMap(Screen->GetTileWarpScreen(tilewarp), dmapID));
  2515. int warptype = Screen->GetTileWarpType(tilewarp);
  2516. int curmap = Game->GetCurMap();
  2517. int curdmap = Game->GetCurDMap();
  2518. int curscreen = Game->GetCurScreen();
  2519. int retsquare = Screen->TileWarpReturnSquare[tilewarp];
  2520. bool doItem = itemid>=0;
  2521. while(true)
  2522. {
  2523. if(Distance(this->X, this->Y, Link->X, Link->Y)<24)
  2524. {
  2525. md->TileWarpDMap[TILEWARP_A] = curdmap;
  2526. md->TileWarpScreen[TILEWARP_A] = curscreen;
  2527. md->SideWarpDMap[SIDEWARP_A] = curdmap;
  2528. md->SideWarpScreen[SIDEWARP_A] = curscreen;
  2529. md->TileWarpType[TILEWARP_A] = warptype;
  2530. md->SideWarpType[SIDEWARP_A] = warptype;
  2531. md->TileWarpReturnSquare[TILEWARP_A] = retsquare;
  2532. md->SideWarpReturnSquare[SIDEWARP_A] = retsquare;
  2533. if(doItem)
  2534. {
  2535. md->State[ST_SPECIALITEM] = Screen->State[ST_SPECIALITEM];
  2536. unless(Screen->State[ST_SPECIALITEM])
  2537. {
  2538. md->NextMap = curmap;
  2539. md->NextScreen = curscreen;
  2540. md->NoCarry = CARRY_ONLY_SPECIALITEM;
  2541. md->Script = cachedData[CACHED_SPECIALITEM_SCRIPT];
  2542. md->InitD[0] = itemid;
  2543. }
  2544. }
  2545. while(Distance(this->X, this->Y, Link->X, Link->Y)<24) Waitframe();
  2546. }
  2547. Waitframe();
  2548. }
  2549. }
  2550. }
  2551.  
  2552. screendata script SpawnSpecialItem
  2553. {
  2554. define DEFAULT_X = (256/2)-8;
  2555. define DEFAULT_Y = (176/2)-8;
  2556. /**
  2557. * Setup:
  2558. * d0: Item ID (ignore if using this with CaveItemRoomWarp)
  2559. * d1: Item X position
  2560. * d2: Item Y position
  2561. */
  2562. void run(int spawnItemID, int itemX, int itemY)
  2563. {
  2564. if(this->State[ST_SPECIALITEM]) return;
  2565. unless(itemX) itemX = DEFAULT_X;
  2566. unless(itemY) itemY = DEFAULT_Y;
  2567. item spitem = CreateItemAt(spawnItemID, itemX, itemY);
  2568. spitem->Pickup = IP_ST_SPECIALITEM | IP_HOLDUP;
  2569. }
  2570. }
  2571.  
  2572. npc script FleshyDodongo
  2573. {
  2574. void run()
  2575. {
  2576. //Make the first instance of the enemy invisible
  2577. this->DrawYOffset = -1000;
  2578. this->CollDetection = false;
  2579.  
  2580. //Spawn a second enemy for the body with no script
  2581. npc body = CreateNPCAt(this->ID, this->X, this->Y);
  2582. body->Script = 0;
  2583. body->Extend = 3;
  2584.  
  2585. int vars[16];
  2586. //vars[0] - Animation Clock
  2587.  
  2588. while(true)
  2589. {
  2590. //The controller enemy handles movement
  2591. this->ConstantWalk({this->Rate, this->Homing, this->Hunger});
  2592. //Then update's the body's position and animation
  2593. FD_UpdateBody(this, vars, body);
  2594.  
  2595. //When the body dies, center it and kill the controller too
  2596. if(body->HP<=0)
  2597. {
  2598. int x = CenterX(body);
  2599. int y = CenterY(body);
  2600. body->X = x-8;
  2601. body->Y = y-8;
  2602. body->TileWidth = 1;
  2603. body->TileHeight = 1;
  2604. body->HitWidth = 16;
  2605. body->HitHeight = 16;
  2606. this->HP = -1000;
  2607. this->ItemSet = 0;
  2608. Quit();
  2609. }
  2610.  
  2611. Waitframe();
  2612. }
  2613. }
  2614. void FD_UpdateBody(npc this, int vars, npc body)
  2615. {
  2616. ++vars[0];
  2617. //Get the enemy's current frame based off F.Rate
  2618. int f4 = Floor(vars[0]/(this->ASpeed/4));
  2619. //Keep the frame wrapped from 0-3
  2620. if(f4==4)
  2621. {
  2622. f4 = 0;
  2623. vars[0] = 0;
  2624. }
  2625.  
  2626. //Update tiles, hitboxes, and position based on the controller's
  2627. switch(this->Dir)
  2628. {
  2629. case DIR_DOWN:
  2630. body->X = this->X;
  2631. body->Y = this->Y-16;
  2632. body->TileWidth = 1;
  2633. body->TileHeight = 2;
  2634. body->HitWidth = 16;
  2635. body->HitHeight = 32;
  2636. body->Tile = this->OriginalTile + 4 + f4;
  2637. body->OriginalTile = body->Tile;
  2638.  
  2639. break;
  2640. case DIR_LEFT:
  2641. body->X = this->X;
  2642. body->Y = this->Y;
  2643. body->TileWidth = 2;
  2644. body->TileHeight = 1;
  2645. body->HitWidth = 32;
  2646. body->HitHeight = 16;
  2647. body->Tile = this->OriginalTile + 40 + f4 * 2;
  2648. body->OriginalTile = body->Tile;
  2649.  
  2650. break;
  2651. case DIR_RIGHT:
  2652. body->X = this->X-16;
  2653. body->Y = this->Y;
  2654. body->TileWidth = 2;
  2655. body->TileHeight = 1;
  2656. body->HitWidth = 32;
  2657. body->HitHeight = 16;
  2658. body->Tile = this->OriginalTile + 60 + f4 * 2;
  2659. body->OriginalTile = body->Tile;
  2660.  
  2661. break;
  2662. default:
  2663. body->X = this->X;
  2664. body->Y = this->Y;
  2665. body->TileWidth = 1;
  2666. body->TileHeight = 2;
  2667. body->HitWidth = 16;
  2668. body->HitHeight = 32;
  2669. body->Tile = this->OriginalTile + f4;
  2670. body->OriginalTile = body->Tile;
  2671. }
  2672. }
  2673. }
  2674.  
  2675. npc script wolfie
  2676. {
  2677. void run()
  2678. {
  2679. int clks[1];
  2680. while(1)
  2681. {
  2682. this->ConstantWalk({this->Rate, this->Homing, this->Hunger});
  2683. nmes::transform2x1(this,clks);
  2684. Waitframe();
  2685. }
  2686. }
  2687. }
  2688.  
  2689. namespace nmes
  2690. {
  2691. void transform2x1(npc n, int clk)
  2692. {
  2693. ++clk[0];
  2694. int f4 = Floor(clk[0]/(n->ASpeed/4));
  2695. if( f4 >= 4 ) { f4 = 0; clk[0] = 0;}
  2696. switch(n->Dir)
  2697. {
  2698. case DIR_DOWN:
  2699. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 4 + f4;
  2700. n->OriginalTile = n->Tile;
  2701. n->HitXOffset = 0;
  2702. n->HitYOffset = -16;
  2703. n->DrawXOffset = 0;
  2704. n->DrawYOffset = -16;
  2705. n->TileWidth = 1;
  2706. n->TileHeight = 2;
  2707. n->HitWidth = 16;
  2708. n->HitHeight = 32;
  2709. break;
  2710. case DIR_RIGHT:
  2711. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 60 + (f4 * 2);
  2712. n->OriginalTile = n->Tile;
  2713. n->HitXOffset = -16;
  2714. n->HitYOffset = 0;
  2715. n->DrawXOffset = -16;
  2716. n->DrawYOffset = 0;
  2717. n->TileWidth = 2;
  2718. n->TileHeight = 1;
  2719. n->HitWidth = 32;
  2720. n->HitHeight = 16;
  2721. break;
  2722. case DIR_LEFT:
  2723. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 40 + (f4 *2);
  2724. n->OriginalTile = n->Tile;
  2725. n->TileWidth = 2;
  2726. n->TileHeight = 1;
  2727. n->HitWidth = 32;
  2728. n->HitHeight = 16;
  2729. n->HitXOffset = 0;
  2730. n->HitYOffset = 0;
  2731. n->DrawXOffset = 0;
  2732. n->DrawYOffset = 0;
  2733. break;
  2734. case DIR_UP:
  2735. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + f4;
  2736. n->OriginalTile = n->Tile;
  2737. n->TileWidth = 1;
  2738. n->TileHeight = 2;
  2739. n->HitWidth = 16;
  2740. n->HitHeight = 32;
  2741. n->HitXOffset = 0;
  2742. n->HitYOffset = 0;
  2743. n->DrawXOffset = 0;
  2744. n->DrawYOffset = 0;
  2745. break;
  2746.  
  2747. }
  2748. }
  2749. }
  2750.  
  2751. ffc script chestSound{
  2752. void run(int sfx, int comboID){
  2753. while(true){
  2754. if ( Screen->ComboD[ComboAt(this->X, this->Y)] == comboID && sfx ) {
  2755. Game->PlaySound(sfx);
  2756. this->Data = 0;
  2757. this->Script = 0;
  2758. Quit();
  2759. }
  2760. Waitframe();
  2761. }
  2762. }
  2763. }
  2764.  
  2765. item script SlashScroll
  2766. {
  2767. void run()
  2768. {
  2769. Game->Generic[GEN_CANSLASH] = 1;
  2770. }
  2771. }
  2772.  
  2773.  
  2774.  
  2775. npc script wolfie2
  2776. {
  2777. void run()
  2778. {
  2779. int clks[1];
  2780. lweapon bite = Screen->CreateLWeapon(EW_SCRIPT1);
  2781. bite->X = this->X;
  2782. bite->Y = this->Y;
  2783. bite->HitHeight = 8;
  2784. bite->HitWidth = 16;
  2785. bite->DrawYOffset = -32768;
  2786. bite->Damage = 2;
  2787. while(1)
  2788. {
  2789. this->ConstantWalk({this->Rate, this->Homing, this->Hunger});
  2790. unless(bite->isValid())
  2791. {
  2792. bite = Screen->CreateLWeapon(EW_SCRIPT1);
  2793. bite->DrawYOffset = -32768;
  2794. bite->Damage = 2;
  2795. }
  2796. if(bite->isValid())
  2797. {
  2798. wolfnme::positionbite(this, bite);
  2799. wolfnme::transformbite(this, bite);
  2800.  
  2801. }
  2802. Waitdraw();
  2803. wolfnme::transform2x1(this,clks);
  2804. Waitframe();
  2805. }
  2806. }
  2807. }
  2808.  
  2809. namespace wolfnme
  2810. {
  2811. void positionbite(npc n, lweapon bite)
  2812. {
  2813. switch(n->Dir)
  2814. {
  2815. case DIR_UP:
  2816. bite->X = n->X; bite->Y = n->Y -1; bite->HitYOffset = -2; bite->HitXOffset = 0; break;
  2817. case DIR_DOWN:
  2818. bite->X = n->X; bite->Y = n->Y + 1; bite->HitYOffset = 24; bite->HitXOffset = 0; break;
  2819. case DIR_LEFT:
  2820. bite->X = n->X - 1; bite->Y = ((n->Y > 0) ? n->Y : n->Y + 1); bite->HitYOffset = 0; bite->HitXOffset = -2; break;
  2821. case DIR_RIGHT:
  2822. bite->X = n->X + 1; bite->Y = ((n->Y > 0) ? n->Y : n->Y + 1); bite->HitYOffset = 0; bite->HitXOffset = 25; break;
  2823. }
  2824. }
  2825. void transformbite(npc n, lweapon l)
  2826. {
  2827. switch(n->Dir)
  2828. {
  2829. case DIR_DOWN:
  2830. case DIR_UP:
  2831. {
  2832. l->HitWidth = 16;
  2833. l->HitHeight = 8;
  2834. break;
  2835. }
  2836. case DIR_RIGHT:
  2837. case DIR_LEFT:
  2838. {
  2839. l->HitWidth = 8;
  2840. l->HitHeight = 16;
  2841. break;
  2842. }
  2843. }
  2844. }
  2845.  
  2846. void transform2x1(npc n, int clk)
  2847. {
  2848. ++clk[0];
  2849. int f4 = Floor(clk[0]/(n->ASpeed/4));
  2850. if( f4 >= 4 ) { f4 = 0; clk[0] = 0;}
  2851. switch(n->Dir)
  2852. {
  2853. case DIR_DOWN:
  2854. {
  2855. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 4 + f4;
  2856. n->OriginalTile = n->Tile;
  2857. n->TileWidth = 1;
  2858. n->TileHeight = 2;
  2859. n->HitWidth = 16;
  2860. n->HitHeight = 32;
  2861. break;
  2862. }
  2863. case DIR_RIGHT:
  2864. {
  2865. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 60 + (f4 * 2);
  2866. n->OriginalTile = n->Tile;
  2867. n->TileWidth = 2;
  2868. n->TileHeight = 1;
  2869. n->HitWidth = 32;
  2870. n->HitHeight = 16;
  2871. break;
  2872. }
  2873. case DIR_LEFT:
  2874. {
  2875. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + 40 + (f4 *2);
  2876. n->OriginalTile = n->Tile;
  2877. n->TileWidth = 2;
  2878. n->TileHeight = 1;
  2879. n->HitWidth = 32;
  2880. n->HitHeight = 16;
  2881. break;
  2882. }
  2883. case DIR_UP:
  2884. {
  2885. n->Tile = (Game->LoadNPCData(n->ID)->Tile) + f4;
  2886. n->OriginalTile = n->Tile;
  2887. n->TileWidth = 1;
  2888. n->TileHeight = 2;
  2889. n->HitWidth = 16;
  2890. n->HitHeight = 32;
  2891. break;
  2892. }
  2893. }
  2894. }
  2895. }
  2896.  
  2897.  
  2898. ////////////////////////////////
  2899. /// Music.zh ///
  2900. /// v1.3.6 - 26th Mar, 2019 ///
  2901. /// By: ZoriaRPG ///
  2902. ////////////////////////////////////////////////////////////////////////////////////////////////////
  2903. /// A series of FFCs, and utility functions for playing MIDIs, Enhanced Music, and Sound Effects ///
  2904. /// 1.3.3: Optimisation for inclusion with ZC 2.53 Gamma 4 ///
  2905. /// 1.3.4: Fixes to NPC_MIDI and NPC_Music ///
  2906. /// 1.3.5: More Fixes to NPC_MIDI and NPC_Music ///
  2907. /// 1.3.6: Renamed BossMusic to MusicZH_BossMusic to avoid a conflict with Classic.zh. ///
  2908. ////////////////////////////////////////////////////////////////////////////////////////////////////
  2909.  
  2910. //#include "std.zh"
  2911. //#include "string.zh"
  2912.  
  2913. const int MIDI_DEFEATBOSS = 0; //Set to default midi to play for Victory Music.
  2914. //ZC will use this if enhanced Victory music is not available.
  2915.  
  2916. const int DEFAULT_BOSS_MUSIC = 0; //Sets a default boss music file to play.
  2917.  
  2918. ///////////////
  2919. /// SCRIPTS ///
  2920. ///////////////
  2921.  
  2922.  
  2923. /////////////////////
  2924. /// Sound Effects ///
  2925. /////////////////////
  2926.  
  2927. // Ties SFX to an item, that is otherwise normally hardcoded. used for the Sonic Wand in LoE.
  2928.  
  2929. item script playSound
  2930. {
  2931. void run(int sfx)
  2932. {
  2933. Game->PlaySound(sfx);
  2934. }
  2935. }
  2936.  
  2937. /////////////////
  2938. /// MIDI Only ///
  2939. /////////////////
  2940.  
  2941. //Plays MIDI specified at D0. Place on a screen, to change the MIDI for that screen, only.
  2942. //Plays at all times on that screen, and uses no conditions.
  2943.  
  2944. ffc script playMIDI
  2945. {
  2946. void run(int midiNumber)
  2947. {
  2948. Game->PlayMIDI(midiNumber);
  2949. }
  2950. }
  2951.  
  2952. /////////////////////////
  2953. /// Conditional MIDIs ///
  2954. /////////////////////////
  2955.  
  2956.  
  2957.  
  2958. //play a MIDI while an enemy with a specific ID is on-screen
  2959.  
  2960. ffc script NPC_MIDI
  2961. {
  2962. void run(int npc_ID, int midi)
  2963. {
  2964. //int originalMIDi = //share these two
  2965. //int originalMusic[3] = //midi, enh music, track
  2966. //store the normal midi or music
  2967. //check for the npc and while it is on-screen
  2968. //change the midi
  2969. Waitframes(6);
  2970. //LogPrint("NPC_MIDI passed %s \n", "Waitframes(1)");
  2971. //if it dies, change back
  2972. int q[4]; npc n; bool found;
  2973. int enh_music[256] = {0};
  2974. Game->GetDMapMusicFilename(Game->GetCurDMap(), enh_music);
  2975.  
  2976. int enh_trk = Game->GetDMapMusicTrack(Game->GetCurDMap());
  2977. for ( q[0] = 0; q[0] < 256; ++q[0] ) { if ( enh_music[q] == ' ' ) enh_music[q] = 0; } //kill the space.
  2978. bool enhanced = ( enh_music[0] != 0 ); //is the dmap music enhanced?
  2979.  
  2980. int originalmusic = Game->DMapMIDI[Game->GetCurDMap()];
  2981. while(!Screen->NumNPCs())
  2982. {
  2983. //LogPrint("NPC_MIDI is %s \n", "Waiting (!Screen->NumNPCs())");
  2984. Waitframe();
  2985. }
  2986. while(true){
  2987. for ( q[0] = Screen->NumNPCs(); q[0] > 0; --q[0] ) {
  2988. n = Screen->LoadNPC(q);
  2989. if ( n->ID == npc_ID )
  2990. {
  2991. //LogPrint("NPC_MIDI %s \n", "matched the input npc");
  2992. q[1] = 1; break;
  2993. }
  2994. q[1] = 0;
  2995. }
  2996. if ( q[1] ) //found the npc
  2997. {
  2998. //LogPrint("NPC_MIDI %s \n", "if(q[1])");
  2999. if ( !q[2] )
  3000. {
  3001. //LogPrint("NPC_MIDI %s \n", "if(!q[2])");
  3002. Game->PlayMIDI( midi );
  3003. q[2] = 1;
  3004. }
  3005. }
  3006. if ( q[2] ) break;
  3007.  
  3008. Waitframe();
  3009. }
  3010. bool stillalive;
  3011.  
  3012. while(1)
  3013. {
  3014. for ( int w = Screen->NumNPCs(); w > 0; --w )
  3015. {
  3016. npc n = Screen->LoadNPC(w);
  3017. if ( n->ID == npc_ID )
  3018. {
  3019. //LogPrint("npc_ID is: %d \n", npc_ID);
  3020. //LogPrint("NPC_MIDI is at %s \n", "still alive");
  3021. stillalive = true;
  3022. break;
  3023. }
  3024. stillalive = false;
  3025. }
  3026. if ( stillalive ) { Waitframe(); continue; }
  3027. if ( !stillalive )
  3028. {
  3029. //LogPrint("NPC_MIDI is at %s \n", "!still alive");
  3030. break;
  3031. }
  3032. Waitframe();
  3033. }
  3034.  
  3035. //LogPrint("NPC_MIDI is at %s \n", "!NumNPCsOf(npc_id)");
  3036. Waitframes(10);
  3037. //LogPrint("NPC_MIDI %s \n", "PlayEnhancedMusic");
  3038. Game->PlayEnhancedMusic(enh_music, enh_trk);
  3039.  
  3040. if ( !enhanced )
  3041. {
  3042. //LogPrint("NPC_MIDI %s \n", "!enhanced");
  3043. Game->PlayMIDI(originalmusic);
  3044. }
  3045.  
  3046. }
  3047. }
  3048.  
  3049. //play enhanced music while an enemy with a specific ID is on-screen
  3050.  
  3051. ffc script NPC_Music
  3052. {
  3053. void run(int npc_ID, int music_string, int track)
  3054. {
  3055. //int originalMIDi = //share these two
  3056. //int originalMusic[3] = //midi, enh music, track
  3057. //store the normal midi or music
  3058. //check for the npc and while it is on-screen
  3059. //change the midi
  3060. Waitframes(6);
  3061. //if it dies, change back
  3062. int q[4]; npc n; bool found;
  3063. int enh_music[256] = {0};
  3064. Game->GetDMapMusicFilename(Game->GetCurDMap(), enh_music);
  3065.  
  3066. int enh_trk = Game->GetDMapMusicTrack(Game->GetCurDMap());
  3067. for ( q[0] = 0; q[0] < 256; ++q[0] ) { if ( enh_music[q] == ' ' ) enh_music[q] = 0; } //kill the space.
  3068. bool enhanced = ( enh_music[0] != 0 ); //is the dmap music enhanced?
  3069. bool playing;
  3070.  
  3071. int originalmusic = Game->DMapMIDI[Game->GetCurDMap()];
  3072. while(!Screen->NumNPCs()) Waitframe();
  3073.  
  3074. while(true){
  3075. for ( q[0] = Screen->NumNPCs(); q[0] > 0; --q[0] )
  3076. {
  3077. n = Screen->LoadNPC(q);
  3078. if ( n->ID == npc_ID )
  3079. {
  3080. q[1] = 1; break;
  3081. }
  3082. q[1] = 0;
  3083. }
  3084. if ( q[1] )
  3085. {
  3086. if ( !q[2] )
  3087. {
  3088. playing = PlayEnhMusicFile(music_string, track);
  3089. q[2] = 1;
  3090. }
  3091. }
  3092. if ( q[2] ) break;
  3093.  
  3094. Waitframe();
  3095. }
  3096. bool stillalive;
  3097. while(1)
  3098. {
  3099. for ( int w = Screen->NumNPCs(); w > 0; --w )
  3100. {
  3101. npc n = Screen->LoadNPC(w);
  3102. if ( n->ID == npc_ID )
  3103. {
  3104. //LogPrint("npc_ID is: %d \n", npc_ID);
  3105. //LogPrint("NPC_MIDI is at %s \n", "still alive");
  3106. stillalive = true;
  3107. break;
  3108. }
  3109. stillalive = false;
  3110. }
  3111. if ( stillalive ) { Waitframe(); continue; }
  3112. if ( !stillalive )
  3113. {
  3114. //LogPrint("NPC_MIDI is at %s \n", "!still alive");
  3115. break;
  3116. }
  3117. Waitframe();
  3118. }
  3119. //LogPrint("NPC_MIDI is at %s \n", "!NumNPCsOf(npc_id)");
  3120. Waitframes(10);
  3121. //LogPrint("NPC_MIDI %s \n", "PlayEnhancedMusic");
  3122. Game->PlayEnhancedMusic(enh_music, enh_trk);
  3123.  
  3124. if ( enhanced ) Game->PlayEnhancedMusic(enh_music, enh_trk);
  3125.  
  3126. else Game->PlayMIDI(originalmusic);
  3127. }
  3128. }
  3129.  
  3130. // These scripts will play MIDI files based on conditions set in the script args.
  3131.  
  3132. // D0: MIDI file to play while boss is on the screen.
  3133. // D1: The Screen Register (Screen->D[reg]) to use.
  3134. // D2: Victory MIDI to play when boss is defeated. If set to 0, the MIDI set by constant MIDI_DEFEATBOSS plays.
  3135. // D3: The duration of the victory music.
  3136. //
  3137. // If set to 0, the track will not play.
  3138. // If set to greater than 0, the track will play for a specific duration, as follows:
  3139. // To set using minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
  3140. // e.g. 00005.0260 is 5 mins, 26 seconds.
  3141. // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
  3142. // If you wish to specify the duration in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
  3143. // e.g. 10526.1023 = 5,261,023 frames.
  3144. // e.g. 10001.3591 = 13,591 frames.
  3145. //
  3146. // D4: The enemy ID of the 'boss':
  3147. //
  3148. // A value of zero here, instructs the FFC not to change the Screen->D[reg] value. Leave this at zero, if the enemy does this.
  3149. // Otherwise, set this to -1 (negative one) if you want the Victory music to play when all screen NPCs are dead...or...
  3150. // a positive value matching an enemy ID that is on the screen, if you want to play the Victory music when all enemies with that ID are dead.
  3151.  
  3152.  
  3153. ffc script MusicZH_BossMusic
  3154. {
  3155. void run(int bossMIDI, int reg, int victoryMIDI, int vict_dur, int enem)
  3156. {
  3157. Waitframes(6);
  3158. int curScreen = Game->GetCurScreen();
  3159. int dat = Game->GetScreenD(curScreen,reg);
  3160. if ( dat == 0 ) {
  3161. if ( bossMIDI > 0 )
  3162. {
  3163. Game->PlayMIDI(bossMIDI);
  3164. }
  3165. else
  3166. {
  3167. Game->PlayMIDI(DEFAULT_BOSS_MUSIC);
  3168. }
  3169. }
  3170. int curDMap = Game->GetCurDMap();
  3171. int stdMIDI = Game->DMapMIDI[curDMap];
  3172.  
  3173.  
  3174. int VictoryClockMethod = _Music_zh__GetDigit(vict_dur, 4);
  3175. int dur;
  3176.  
  3177. if ( VictoryClockMethod == 0 )
  3178. {
  3179. dur = MusicFrames(vict_dur); //Convert victory music into frames.
  3180. }
  3181.  
  3182. if ( VictoryClockMethod > 0 )
  3183. {
  3184. dur = _Music_zh__GetPartialArg(vict_dur,3,8); //Use the full value of loopBossMusic as frame in int.
  3185. }
  3186.  
  3187. while(true)
  3188. {
  3189. dat = Game->GetScreenD(curScreen,reg);
  3190.  
  3191. if ( enem == -1 && !Screen->NumNPCs() )
  3192. {
  3193. Game->SetScreenD(curScreen,reg,1);
  3194. }
  3195. if ( enem == 0 )
  3196. {
  3197. //Should we do anything special?
  3198. //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
  3199. //-1 if we do it based on all enemies being dead.
  3200. //A positive value trips it if there are no enemies of that ID on the screen.
  3201. }
  3202.  
  3203. if ( enem > 0 && !NumNPCsOf(enem) )
  3204. {
  3205. Game->SetScreenD(curScreen,reg,1);
  3206. }
  3207.  
  3208. dat = Game->GetScreenD(curScreen,reg);
  3209.  
  3210.  
  3211. if ( dat > 0 )
  3212. {
  3213. if ( dur > 0 )
  3214. {
  3215. if ( victoryMIDI > 0 )
  3216. {
  3217. Game->PlayMIDI(MIDI_DEFEATBOSS);
  3218. }
  3219. else
  3220. {
  3221. Game->PlayMIDI(MIDI_DEFEATBOSS);
  3222. }
  3223. for ( int q = 0; q <= dur; ++q )
  3224. {
  3225. Waitframe();
  3226. }
  3227. }
  3228. Game->PlayMIDI(stdMIDI);
  3229. }
  3230. Waitframe();
  3231. }
  3232. }
  3233. }
  3234.  
  3235. //////////////////////
  3236. /// Enhanced Music ///
  3237. //////////////////////
  3238.  
  3239. /// These scripts will play 'enhanced music', using values set in script args.
  3240. /// If an enhanced music file is not available (e.g. the player does not have it, or elects
  3241. /// not to use it, then they will play a back-up MIDI file, also set by script args.
  3242.  
  3243. // D0: MIDI number to default to for this boss, if no enhanced music is available.
  3244. // Split argument, high and low at decimal point:
  3245. // #####.xxxx -> Backup MIDI file to play if enhanced BOSS music is not available.
  3246. // xxxxx.#### -> Backup MIDI file to play if enhanced VICTORY music is not available.
  3247. // D1: Screen->D reg to set/check.
  3248. // D2: The duration of the victory music.
  3249. // If set to 0, the track will not play.
  3250. // If set to greater than 0, the track will play for a specific duration, as follows:
  3251. // To set using minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
  3252. // e.g. 00005.0260 is 5 mins, 26 seconds.
  3253. // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
  3254. // If you wish to specify the duration in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
  3255. // e.g. 10526.1023 = 5,261,023 frames.
  3256. // e.g. 10001.3591 = 13,591 frames.
  3257. //
  3258. // D3: The STRING number, and track number, for Boss Music. Split arg, high and low at decimal point:
  3259. // #####.xxxx -> The file number.
  3260. // xxxxx.#### -> The track number to play.
  3261. // Uses string ID from internal strings table.
  3262. // D4: The STRING number, and track number, for Victory Music. Split arg, high and low at decimal point:
  3263. // #####.xxxx -> The file number.
  3264. // xxxxx.#### -> The track number to play.
  3265. // Uses string ID from internal strings table.
  3266. // D5: The point in the track to pause, then loop
  3267. //
  3268. // If set to 0, the track with loop only when it ends.
  3269. // If set to greater than 0, the track will loop befor eit ends, as follows:
  3270. // To loop by setting minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
  3271. // e.g. 00005.0260 is 5 mins, 26 seconds.
  3272. // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
  3273. // If you wish to specify the loop in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
  3274. // e.g. 10526.1023 = 5,261,023 frames.
  3275. // e.g. 10001.3591 = 13,591 frames.
  3276. //
  3277. // D6: This value instructs the FFC to set Screen->D[reg] = 1 when enemies are dead.
  3278. // A value of zero here, instructs the FFC not to change the Screen->D[reg] value. Leave this at zero, if the enemy does this.
  3279. // Otherwise, set this to -1 (negative one) if you want the Victory music to play when all screen NPCs are dead...or...
  3280. // a positive value matching an enemy ID that is on the screen, if you want to play the Victory music when all enemies with that ID are dead.
  3281. //
  3282. // D7: If set to '1' or above, this will trace informationt o allegro.log for you as debug datum.
  3283.  
  3284.  
  3285. //Version 0.44 - Strings set by String Table (ZQuest String Editor, not hardcoded)
  3286.  
  3287. ffc script BossMusicEnhanced_InternalStrings
  3288. {
  3289. //Credit Moosh for reminding me that reading internal strings in the string table is a thing.
  3290. void run(int midiNumber_victoryMidiNumber, int reg, int vict_dur, float musicBoss_trkBoss, float musicVictory_trkVictory, float loopBossMusic, int enem, int debug)
  3291. {
  3292. int curScreen = Game->GetCurScreen();
  3293. int curDMAP = Game->GetCurDMap();
  3294. int curDmap = Game->GetCurDMap();
  3295. int dat = Game->GetScreenD(curScreen,reg);
  3296. int stdMIDI = Game->DMapMIDI[curDMAP];
  3297.  
  3298. int dmapMusicBuffer[512]=" ";
  3299. Game->GetDMapMusicFilename(curDMAP, dmapMusicBuffer);
  3300.  
  3301. int midiNumber = _Music_zh__GetHighArgument(midiNumber_victoryMidiNumber); //#####.xxxx
  3302. int victoryMIDI = _Music_zh__GetLowArgument(midiNumber_victoryMidiNumber); //xxxxx.####
  3303.  
  3304. int musicBoss = _Music_zh__GetHighArgument(musicBoss_trkBoss); //#####.xxxx
  3305. int trkBoss = _Music_zh__GetLowArgument(musicBoss_trkBoss); //xxxxx.####
  3306.  
  3307. int musicVictory = _Music_zh__GetHighArgument(musicVictory_trkVictory);
  3308. int trkVictory = _Music_zh__GetLowArgument(musicVictory_trkVictory); //xxxxx.####
  3309.  
  3310. int dmapTrack = Game->GetDMapMusicTrack(curDMAP);
  3311. int q;
  3312.  
  3313. int boss_buffer[256]=" "; //two-digit number, plus four-digit extension, plus NULL.
  3314. int victory_buffer[256]=" "; //Buffer for Victory Music Filename.
  3315.  
  3316. Game->GetMessage(musicVictory, victory_buffer);
  3317. Game->GetMessage(musicBoss, boss_buffer);
  3318.  
  3319.  
  3320. //Print filenames to allegro.log.
  3321. if ( debug )
  3322. {
  3323. int loading[]="Attempting to load file: ";
  3324. TraceNL();
  3325. TraceS(loading);
  3326. TraceNL();
  3327. TraceS(boss_buffer);
  3328. TraceNL();
  3329. TraceS(loading);
  3330. TraceNL();
  3331. TraceS(victory_buffer);
  3332. TraceNL();
  3333. }
  3334.  
  3335. int playingBoss[]="Playing Boss Music";
  3336. int playingVictory[]="Playing Victory Music";
  3337. int errLoading[]="Error loading track.";
  3338.  
  3339. int LoopClockMethod = _Music_zh__GetDigit(loopBossMusic, 4);
  3340. //Convert mins and seconds.
  3341.  
  3342. int BossMusicDuration;
  3343. if ( LoopClockMethod == 0 )
  3344. {
  3345. BossMusicDuration = MusicFrames(loopBossMusic); //Convert loopBossMusic into time.
  3346. }
  3347. if ( LoopClockMethod > 0 )
  3348. {
  3349. BossMusicDuration = _Music_zh__GetPartialArg(loopBossMusic,3,8); //Use the full value of loopBossMusic as frame in int.
  3350. }
  3351.  
  3352. int VictoryClockMethod = _Music_zh__GetDigit(vict_dur, 4);
  3353. int dur;
  3354.  
  3355. if ( VictoryClockMethod == 0 )
  3356. {
  3357. dur = MusicFrames(vict_dur); //Convert victory music into frames.
  3358. }
  3359.  
  3360. if ( VictoryClockMethod > 0 )
  3361. {
  3362. dur = _Music_zh__GetPartialArg(vict_dur,3,8); //Use the full value of loopBossMusic as frame in int.
  3363. }
  3364. for ( q = 0; q < 256; q++ ) { if ( boss_buffer[q] == ' ' ) boss_buffer[q] = 0; } //kill the space.
  3365. for ( q = 0; q < 256; q++ ) { if ( victory_buffer[q] == ' ' ) victory_buffer[q] = 0; } //kill the space.
  3366. bool playing = false;
  3367. Waitframes(6); //Wait for enemies to spawn. //Moved up here in 1.3.4
  3368. while(true)
  3369. {
  3370. //Waitframes(5); 1.3.4
  3371. dat = Game->GetScreenD(curScreen,reg);
  3372. //Waitframes(6); //Wait for enemies to spawn. 1.3.4
  3373. //Set Screen->D[reg] = 1 if the enemy is dead.
  3374. if ( enem == -1 && !Screen->NumNPCs() )
  3375. {
  3376. Game->SetScreenD(curScreen,reg,1);
  3377. }
  3378. if ( enem == 0 )
  3379. {
  3380. //Should we do anything special?
  3381. //A zero value is intended to be used if we don't want the FFC to set Screen->D to 1.
  3382. //-1 if we do it based on all enemies being dead.
  3383. //A positive value trips it if there are no enemies of that ID on the screen.
  3384. }
  3385.  
  3386. if ( enem > 0 && !NumNPCsOf(enem) )
  3387. {
  3388. Game->SetScreenD(curScreen,reg,1);
  3389. }
  3390.  
  3391. dat = Game->GetScreenD(curScreen,reg);
  3392.  
  3393. if ( dat == 0 && loopBossMusic == 0 && !playing )
  3394. {
  3395. Game->PlayEnhancedMusic(boss_buffer, trkBoss);
  3396.  
  3397. if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
  3398. {
  3399. if ( midiNumber > 0 )
  3400. {
  3401. Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
  3402. }
  3403. else
  3404. {
  3405. Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default music if midiNumber is set to '0'.
  3406. }
  3407.  
  3408. }
  3409. playing = true;
  3410. }
  3411.  
  3412. if ( dat == 0 && loopBossMusic > 0 )
  3413. {
  3414.  
  3415. //set up music loop
  3416. for ( int q = BossMusicDuration; q >=0; --q )
  3417. {
  3418. if ( q == BossMusicDuration && dat == 0 )
  3419. {
  3420. Game->PlayEnhancedMusic(boss_buffer, trkBoss);
  3421. if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
  3422. {
  3423. Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
  3424. }
  3425. }
  3426. if ( enem == -1 && !Screen->NumNPCs() )
  3427. {
  3428. Game->SetScreenD(curScreen,reg,1);
  3429. }
  3430. if ( enem == 0 )
  3431. {
  3432. //Should we do anything special?
  3433. //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
  3434. //-1 if we do it based on all enemies being dead.
  3435. //A positive value trips it if there are no enemies of that ID on the screen.
  3436. }
  3437. if ( enem > 0 && !NumNPCsOf(enem) )
  3438. {
  3439. Game->SetScreenD(curScreen,reg,1);
  3440. }
  3441. dat = Game->GetScreenD(curScreen,reg);
  3442. if ( dat > 0 )
  3443. {
  3444. break;
  3445. }
  3446. Waitframe();
  3447.  
  3448. }
  3449. }
  3450.  
  3451. if ( dat == 0 && loopBossMusic == 0 && !playing )
  3452. {
  3453. Game->PlayEnhancedMusic(boss_buffer, trkBoss);
  3454. if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
  3455. {
  3456. if ( midiNumber > 0 )
  3457. {
  3458. Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
  3459. }
  3460. else
  3461. {
  3462. Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Plays default if not specified.
  3463. }
  3464. }
  3465. playing = true;
  3466.  
  3467. }
  3468.  
  3469. dat = Game->GetScreenD(curScreen,reg);
  3470. if ( dat > 0 )
  3471. {
  3472. if ( dur > 0 )
  3473. {
  3474. Game->PlayEnhancedMusic(victory_buffer, trkVictory);
  3475. if ( ! Game->PlayEnhancedMusic(victory_buffer, trkVictory) )
  3476. {
  3477. if ( victoryMIDI > 0 )
  3478. {
  3479. Game->PlayMIDI(victoryMIDI);
  3480. }
  3481. else
  3482. {
  3483. Game->PlayMIDI(MIDI_DEFEATBOSS); //Plays default if Victory MIDI not specified.
  3484. }
  3485.  
  3486. }
  3487. for ( int q = 0; q <= dur; ++q )
  3488. {
  3489. Waitframe(); //Pause for duration of victory music.
  3490. }
  3491. }
  3492. Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack);
  3493. if ( ! Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack) )
  3494. {
  3495. Game->PlayMIDI(stdMIDI);
  3496. }
  3497. Quit();
  3498. }
  3499. Waitframe();
  3500. }
  3501.  
  3502. }
  3503. }
  3504.  
  3505. // D0: MIDI number to default to for this boss, if no enhanced music is available.
  3506. // Split argument, high and low at decimal point:
  3507. // #####.xxxx -> Backup MIDI file to play if enhanced BOSS music is not available.
  3508. // xxxxx.#### -> Backup MIDI file to play if enhanced VICTORY music is not available.
  3509. // D1: Screen->D reg to set/check.
  3510. // D2: Set to a value of '1' or higher, to use durations.
  3511. // D3: Sets file type for both enhanced music tracks. Split argument, high and low at decimal point:
  3512. // xxx##.xxxx -> Type for Boss Music file
  3513. // xxxxx.xx## -> Type for Victory Music file
  3514. // D4: The file number, and track number, for Boss Music. Split arg, high and low at decimal point:
  3515. // #####.xxxx -> The file number.
  3516. // xxxxx.#### -> The track number to play.
  3517. // D5: The file number, and track number, for Victory Music. Split arg, high and low at decimal point:
  3518. // #####.xxxx -> The file number.
  3519. // xxxxx.#### -> The track number to play.
  3520. // D6: The point in the track to pause, then loop.
  3521. //
  3522. // If set to 0, the track with loop only when it ends.
  3523. // If set to greater than 0, the track will loop befor eit ends, as follows:
  3524. // To loop by setting minutes, and seconds, set up minutes as the integer portion of the arg, and seconds as the decimal portion:
  3525. // e.g. 00005.0260 is 5 mins, 26 seconds.
  3526. // This works to a fineness of 1/10 second, so 00010.0136 is 10 minutes, 13.6 seconds.
  3527. // If you wish to specify the loop in frames, set the ten-thousands place to '1', and the rest of the value to the number of frames.
  3528. // e.g. 10526.1023 = 5,261,023 frames.
  3529. // e.g. 10001.3591 = 13,591 frames.
  3530. //
  3531. // D7: This value instructs the FFC to set Screen->D[reg] = 1 when enemies are dead.
  3532. // #####.xxxx -> A value of zero here, instructs the FFC not to change the Screen->D[reg] value. Leave this at zero, if the enemy does this.
  3533. // Otherwise, set this to -1 (negative one) if you want the Victory music to play when all screen NPCs are dead...or...
  3534. // a positive value matching an enemy ID that is on the screen, if you want to play the Victory music when all enemies with that ID are dead.
  3535. // xxxxx.#### -> Set to '1' or higher to enable debugging reports to allegro.log.
  3536. //
  3537.  
  3538. //Version 0.44 (Numbered Files)
  3539.  
  3540. ffc script BossMusicEnhanced_old
  3541. {
  3542. void run(int midiNumber_victoryMidiNumber, int reg, int victoryDur, float musicType_musicTypeVictory, float musicBoss_trkBoss, float musicVictory_trkVictory, float loopBossMusic, int enem_debug)
  3543. {
  3544. int curScreen = Game->GetCurScreen();
  3545. int curDMAP = Game->GetCurDMap();
  3546. int curDmap = Game->GetCurDMap();
  3547. int dat = Game->GetScreenD(curScreen,reg);
  3548. int stdMIDI = Game->DMapMIDI[curDMAP];
  3549. int enem = _Music_zh__GetHighArgument(enem_debug);
  3550. int debug= _Music_zh__GetLowArgument(enem_debug);
  3551.  
  3552. int dmapMusicBuffer[512]=" ";
  3553. Game->GetDMapMusicFilename(curDMAP, dmapMusicBuffer);
  3554.  
  3555. int midiNumber = _Music_zh__GetHighArgument(midiNumber_victoryMidiNumber); //#####.xxxx
  3556. int victoryMIDI = _Music_zh__GetLowArgument(midiNumber_victoryMidiNumber); //xxxxx.####
  3557.  
  3558. int musicType = _Music_zh__GetHighArgument(musicType_musicTypeVictory); //xxx##.xxxx
  3559. int musicType_Victory = _Music_zh__GetLowArgument(musicType_musicTypeVictory); //xxxxx.xx##
  3560.  
  3561. int musicBoss = _Music_zh__GetHighArgument(musicBoss_trkBoss); //#####.xxxx
  3562. int trkBoss = _Music_zh__GetLowArgument(musicBoss_trkBoss); //xxxxx.####
  3563.  
  3564. int musicVictory = _Music_zh__GetHighArgument(musicVictory_trkVictory); //#####.xxxx
  3565. int trkVictory = _Music_zh__GetLowArgument(musicVictory_trkVictory); //xxxxx.####
  3566.  
  3567. int dmapTrack = Game->GetDMapMusicTrack(curDMAP);
  3568. int mp3[]=".mp3";
  3569. int vgm[]=".vgm";
  3570. int nsf[]=".nsf";
  3571. int ogg[]=".ogg";
  3572. int s3m[]=".s3m";
  3573. int mod[]=".mod";
  3574. int spc[]=".spc";
  3575. int gym[]=".gym";
  3576. int gbs[]=".gbs";
  3577. int it_format[]=".it";
  3578. int xm[]=".xm";
  3579.  
  3580. int boss_buffer[7]=" "; //two-digit number, plus four-digit extension, plus NULL.
  3581. int victory_buffer[7]=" "; //Buffer for Victory Music Filename.
  3582. int strBoss[2]=" "; //The two digit value of musicBoss arg.
  3583. int strVictory[2]=" "; //The two digit value of musicVictory is stored here.
  3584. //int bossMusic[]=" "; //Must read value from enhBoss, append .mp3 to it, and
  3585.  
  3586.  
  3587. ///Set up Boss Music Filename String
  3588. itoa(strBoss, musicBoss); //Copy the value of arg musicBoss into string strBoss.
  3589. strncpy(boss_buffer, strBoss, 2); //Copy filename (two-digit number) to buffer.
  3590. if ( musicType == 0 ) strcat(boss_buffer, mp3); //Append datatype to buffer (MP3)
  3591. else if ( musicType == 1 ) strcat(boss_buffer, vgm); //Append datatype to buffer ( Video Game Music format)
  3592. else if ( musicType == 2 ) strcat(boss_buffer, nsf); //Append datatype to buffer ( NES Sound File )
  3593. else if ( musicType == 3 ) strcat(boss_buffer, ogg); //Append datatype to buffer ( The Xiph.org open music format )
  3594. else if ( musicType == 4 ) strcat(boss_buffer, s3m); //Append datatype to buffer ( ScreamTracker 3 module file )
  3595. else if ( musicType == 5 ) strcat(boss_buffer, mod); //Append datatype to buffer ( Tracker Module file )
  3596. else if ( musicType == 6 ) strcat(boss_buffer, spc); //Append datatype to buffer ( Super NES / SuFami soound file )
  3597. else if ( musicType == 7 ) strcat(boss_buffer, gym); //Append datatype to buffer ( Genesis / Megadrive sound file )
  3598. else if ( musicType == 8 ) strcat(boss_buffer, gbs); //Append datatype to buffer ( Gameboy sound file )
  3599. else if ( musicType == 9 ) strcat(boss_buffer, it_format); //Append datatype to buffer ( Impulse Tracker audio file )
  3600. else if ( musicType == 10 ) strcat(boss_buffer, xm); //Append datatype to buffer ( Triton FastTracker 2 'Extended Module' format }
  3601. ///Other formats.
  3602.  
  3603. //Set up Victory Music Filename String
  3604. itoa(strVictory, musicVictory); //Copy the value of arg musicVictory into string strVictory.
  3605. strncpy(victory_buffer, strVictory, 2); //Copy filename (two-digit number) to buffer.
  3606. if ( musicType_Victory == 0 ) strcat(victory_buffer, mp3); //Append datatype to buffer (MP3)
  3607. else if ( musicType_Victory == 1 ) strcat(victory_buffer, vgm); //Append datatype to buffer ( Video Game Music format)
  3608. else if ( musicType_Victory == 2 ) strcat(victory_buffer, nsf); //Append datatype to buffer ( NES Sound File )
  3609. else if ( musicType_Victory == 3 ) strcat(victory_buffer, ogg); //Append datatype to buffer ( The Xiph.org open music format )
  3610. else if ( musicType_Victory == 4 ) strcat(victory_buffer, s3m); //Append datatype to buffer ( ScreamTracker 3 module file )
  3611. else if ( musicType_Victory == 5 ) strcat(victory_buffer, mod); //Append datatype to buffer ( Tracker Module file )
  3612. else if ( musicType_Victory == 6 ) strcat(victory_buffer, spc); //Append datatype to buffer ( Super NES / SuFami soound file )
  3613. else if ( musicType_Victory == 7 ) strcat(victory_buffer, gym); //Append datatype to buffer ( Genesis / Megadrive sound file )
  3614. else if ( musicType_Victory == 8 ) strcat(victory_buffer, gbs); //Append datatype to buffer ( Gameboy sound file )
  3615. else if ( musicType_Victory == 9 ) strcat(victory_buffer, it_format); //Append datatype to buffer ( Impulse Tracker audio file )
  3616. else if ( musicType_Victory == 10 ) strcat(victory_buffer, xm); //Append datatype to buffer ( Triton FastTracker 2 'Extended Module' format }
  3617. ///Other formats.
  3618.  
  3619.  
  3620. //Print filenames to allegro.log.
  3621. if ( debug )
  3622. {
  3623. int loading[]="Attempting to load file: ";
  3624. TraceNL();
  3625. TraceS(loading);
  3626. TraceNL();
  3627. TraceS(boss_buffer);
  3628. TraceNL();
  3629. TraceS(loading);
  3630. TraceNL();
  3631. TraceS(victory_buffer);
  3632. TraceNL();
  3633. }
  3634.  
  3635. int playingBoss[]="Playing Boss Music";
  3636. int playingVictory[]="Playing Victory Music";
  3637. int errLoading[]="Error loading track.";
  3638.  
  3639. int LoopClockMethod = _Music_zh__GetDigit(loopBossMusic, 4);
  3640. //Convert mins and seconds.
  3641.  
  3642.  
  3643. int BossMusicDuration;
  3644. if ( LoopClockMethod == 0 )
  3645. {
  3646. BossMusicDuration = MusicFrames(loopBossMusic); //Convert loopBossMusic into time.
  3647. }
  3648. if ( LoopClockMethod > 0 )
  3649. {
  3650. BossMusicDuration = _Music_zh__GetPartialArg(loopBossMusic,3,8); //Use the full value of loopBossMusic as frame in int.
  3651. }
  3652.  
  3653. int VictoryDuration;
  3654. int VictoryDurMethod = _Music_zh__GetDigit(victoryDur, 4);
  3655. if ( VictoryDurMethod == 0 )
  3656. {
  3657. VictoryDuration = MusicFrames(victoryDur); //Convert loopBossMusic into time.
  3658. }
  3659. if ( VictoryDurMethod > 0 )
  3660. {
  3661. VictoryDuration = _Music_zh__GetPartialArg(victoryDur,3,8); //Use the full value of loopBossMusic as frame in int.
  3662. }
  3663.  
  3664.  
  3665. bool playing = false;
  3666. Waitframes(6); //Wait for enemies to spawn. //Moved up here in 1.3.4
  3667. while(true)
  3668. {
  3669. dat = Game->GetScreenD(curScreen,reg);
  3670. //Waitframes(6); //Wait for enemies to spawn. 1.3.4
  3671. //Set Screen->D[reg] = 1 if the enemy is dead.
  3672. if ( enem == -1 && !Screen->NumNPCs() )
  3673. {
  3674. Game->SetScreenD(curScreen,reg,1);
  3675. }
  3676. if ( enem == 0 )
  3677. {
  3678. //Should we do anything special?
  3679. //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
  3680. //-1 if we do it based on all enemies being dead.
  3681. //A positive value trips it if there are no enemies of that ID on the screen.
  3682. }
  3683.  
  3684. if ( enem > 0 && !NumNPCsOf(enem) )
  3685. {
  3686. Game->SetScreenD(curScreen,reg,1);
  3687. }
  3688.  
  3689. dat = Game->GetScreenD(curScreen,reg);
  3690.  
  3691. if ( dat == 0 && loopBossMusic == 0 && !playing )
  3692. {
  3693. Game->PlayEnhancedMusic(boss_buffer, trkBoss);
  3694.  
  3695. if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
  3696. {
  3697. if ( midiNumber > 0 )
  3698. {
  3699. Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
  3700. }
  3701. else
  3702. {
  3703. Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default if not assigned.
  3704. }
  3705.  
  3706. }
  3707.  
  3708. playing = true;
  3709. }
  3710.  
  3711. if ( dat == 0 && loopBossMusic > 0 )
  3712. {
  3713. //set up music loop
  3714. for ( int q = BossMusicDuration; q >=0; q-- ){
  3715. if ( q == BossMusicDuration && dat == 0 )
  3716. {
  3717.  
  3718. Game->PlayEnhancedMusic(boss_buffer, trkBoss);
  3719. if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
  3720. {
  3721. if ( midiNumber > 0 )
  3722. {
  3723. Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
  3724. }
  3725. else
  3726. {
  3727. Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default if not assigned.
  3728. }
  3729. }
  3730. }
  3731. if ( enem == -1 && !Screen->NumNPCs() )
  3732. {
  3733. Game->SetScreenD(curScreen,reg,1);
  3734. }
  3735. if ( enem == 0 )
  3736. {
  3737. //Should we do anything special?
  3738. //A zero value is intended to be used if we don;t want the FFC to set Screen->D to 1.
  3739. //-1 if we do it based on all enemies being dead.
  3740. //A positive value trips it if there are no enemies of that ID on the screen.
  3741. }
  3742. if ( enem > 0 && !NumNPCsOf(enem) )
  3743. {
  3744. Game->SetScreenD(curScreen,reg,1);
  3745. }
  3746. dat = Game->GetScreenD(curScreen,reg);
  3747. if ( dat > 0 )
  3748. {
  3749. break;
  3750. }
  3751. Waitframe();
  3752.  
  3753. }
  3754. }
  3755.  
  3756. if ( dat == 0 && loopBossMusic == 0 && !playing )
  3757. {
  3758.  
  3759. Game->PlayEnhancedMusic(boss_buffer, trkBoss);
  3760. if ( ! Game->PlayEnhancedMusic(boss_buffer, trkBoss) )
  3761. {
  3762. if ( midiNumber > 0 )
  3763. {
  3764. Game->PlayMIDI(midiNumber); //Play MIDI if enhanced music is not available.
  3765. }
  3766. else
  3767. {
  3768. Game->PlayMIDI(DEFAULT_BOSS_MUSIC); //Play default if not assigned.
  3769. }
  3770. }
  3771. playing = true;
  3772.  
  3773. }
  3774.  
  3775. dat = Game->GetScreenD(curScreen,reg);
  3776. if ( dat > 0 )
  3777. {
  3778. if ( VictoryDuration > 0 )
  3779. {
  3780. Game->PlayEnhancedMusic(victory_buffer, trkVictory);
  3781. if ( ! Game->PlayEnhancedMusic(victory_buffer, trkVictory) )
  3782. {
  3783. if ( victoryMIDI > 0 )
  3784. {
  3785. Game->PlayMIDI(victoryMIDI);
  3786. }
  3787. else
  3788. {
  3789. Game->PlayMIDI(MIDI_DEFEATBOSS);
  3790. }
  3791.  
  3792. }
  3793. for ( int q = 0; q <= VictoryDuration; q++ )
  3794. {
  3795. Waitframe(); //Pause for duration of victory music.
  3796. }
  3797. }
  3798. Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack);
  3799. if ( ! Game->PlayEnhancedMusic(dmapMusicBuffer, dmapTrack) )
  3800. {
  3801. Game->PlayMIDI(stdMIDI);
  3802. }
  3803. Quit();
  3804. }
  3805. Waitframe();
  3806. }
  3807.  
  3808. }
  3809. }
  3810.  
  3811. /////////////////
  3812. /// FUNCTIONS ///
  3813. /////////////////
  3814.  
  3815. //Pass a float to either of these, to convert raw float into mins and seconds as:
  3816. // #####.xxxx = # mins x seconds. Example:
  3817. // 00003.0050 = 3 mins, 5 seconds.
  3818. // 00001.0012 = 1 minute, 5.2 seconds.
  3819.  
  3820. //Timers are functional to a total clock of 3579 seconds (59 mins, 39 seconds).
  3821.  
  3822. int MusicSeconds(float seconds)
  3823. {
  3824. int music_seconds = _Music_zh__GetLowArgument(seconds);
  3825. return music_seconds * 6;
  3826. }
  3827.  
  3828. int MusicMinutes(float mins)
  3829. {
  3830. int music_minutes = _Music_zh__GetHighArgument(mins);
  3831. return music_minutes * 360;
  3832. }
  3833.  
  3834. //Returns total time in frames, so that ZC understands it.
  3835.  
  3836. int MusicFrames(float val)
  3837. {
  3838. int mins = MusicMinutes(val);
  3839. int seconds = MusicSeconds(val);
  3840. return mins+seconds;
  3841. }
  3842.  
  3843.  
  3844. int _Music_zh__GetRemainderAsInt(int v)
  3845. {
  3846. int r = (v - (v << 0)) * 10000;
  3847. return r;
  3848. }
  3849.  
  3850. // This function breaks up the value of an argument into individual digits. It is combined with the function GetDigit below.
  3851.  
  3852.  
  3853. int _Music_zh__GetDigit(int n, int place)
  3854. {
  3855. //GetDigit and related functions by Gleeok
  3856. place = Clamp(place, -4, 4);
  3857. if(place < 0){
  3858. n = _Music_zh__GetRemainderAsInt(n);
  3859. place += 4;
  3860. }
  3861.  
  3862. int r = ((n / Pow(10, place)) % 10) << 0;
  3863. return r;
  3864. }
  3865.  
  3866. int _Music_zh__GetHighArgument(int arg)
  3867. {
  3868. return arg >> 0;
  3869. }
  3870.  
  3871. int _Music_zh__GetLowArgument(int arg)
  3872. {
  3873. return (arg - (arg >> 0)) * 10000;
  3874. }
  3875.  
  3876. int _Music_zh__GetPartialArg(int arg, int place, int num)
  3877. {
  3878. place = Clamp(place, -4, 4);
  3879. int r;
  3880. int adj = 1;
  3881. for(int i = num-1; i > -1; i--)
  3882. {
  3883. if(place - i < -4) continue;
  3884. r += _Music_zh__GetDigit(arg, place - i) * adj;
  3885. adj *= 10;
  3886. }
  3887. return r;
  3888. }
  3889.  
  3890.  
  3891. // Plays enhanced music file by reading the string 'str_id' from Quest->Strings, at a specified track 'track_id'.
  3892. // If track_id is positive, it uses this track.
  3893. // If track_id is negative, it uses the message string equal to the inverse value (so -20 is string ID 20)
  3894. // to set the track ID.
  3895. // Returns true if playing, false otherwise.
  3896. bool PlayEnhMusicFile(int str_id, int track_id)
  3897. {
  3898. int musicBuffer[256]=" ";
  3899. int track_buffer[256]=" ";
  3900. int q; int trk;
  3901. Game->GetMessage(str_id, musicBuffer);
  3902. for ( q = 0; q < 256; ++q ) { if ( musicBuffer[q] == ' ' ) musicBuffer[q] = 0; } //Kill GetMessage trailing spaces.
  3903. if ( track_id < 0 )
  3904. {
  3905. Game->GetMessage((track_id * -1), track_buffer);
  3906. for ( q = 0; q < 256; ++q )
  3907. {
  3908. if ( track_buffer[q] == ' ' ) track_buffer[q] = 0;
  3909. } //Kill GetMessage trailing spaces.
  3910. trk = atoi(track_buffer);
  3911. }
  3912. else trk = track_id;
  3913. //Kill GetMessage trailing spaces.
  3914. bool play = Game->PlayEnhancedMusic(musicBuffer, trk);
  3915. return ( play );
  3916. }
  3917.  
  3918. int Legacy_PlayEnhMusicFile(int str_id, int track_id) { if ( PlayEnhMusicFile(str_id, track_id) ) return 1; return 0; }
  3919.  
  3920. ffc script music_zh_spawnnpc
  3921. {
  3922. void run(int nid)
  3923. {
  3924. int pos;
  3925. for ( int q = 0; q < 176; q++ )
  3926. {
  3927. if ( Screen->ComboF[q] == 37 ) pos = q;
  3928. }
  3929. while(1){
  3930. if ( Collision(this) )
  3931. {
  3932. npc n = Screen->CreateNPC(nid);
  3933.  
  3934. n->X = ComboX(pos); n->Y = ComboY(pos);
  3935. Quit();
  3936. }
  3937. Waitframe();
  3938.  
  3939. }
  3940. }
  3941. }
  3942.  
  3943. void WandSound(int sound)
  3944. {
  3945. int itmA = GetEquipmentA();
  3946. int itmB = GetEquipmentB();
  3947. itemdata ida = Game->LoadItemData(itmA);
  3948. itemdata idb = Game->LoadItemData(itmB);
  3949. if ( ( ida->Family == IC_WAND && Link->PressA ) || ( idb->Family == IC_WAND && Link->PressB ) )
  3950. {
  3951. if ( !NumLWeaponsOf(LW_WAND) ) { Game->PlaySound(sound); }
  3952. }
  3953. }
  3954.  
  3955. global script Music_ZH_Global_Active
  3956. {
  3957. void run(){
  3958. while(true){
  3959. WandSound(30);
  3960. Waitdraw();
  3961. Waitframe();
  3962. }
  3963. }
  3964. }
  3965.  
  3966.  
  3967.  
  3968. ffc script fade
  3969. {
  3970. void run(int warptile)
  3971. {
  3972. bool waiting = true;
  3973. while(waiting) { Waitframe(); }
  3974. this->Data = warptile; this->X = Link->X; this->Y = Link->Y;
  3975. }
  3976. }
  3977.  
  3978. ffc script Hoffs_Message_Script
  3979. {
  3980. void run(int string, int delay, int no_return, int string2, int toggle, int screen_var, int item_id)
  3981. {
  3982. //This variable is used to check if you have entered the screen before
  3983. int screen_check = 1;
  3984.  
  3985. //If you have chosen to use a delay(more then 0)
  3986. if (delay > 0)
  3987. {
  3988. //Wait for "delay" amount of frames. 60 frames = 1 second
  3989. Waitframes(delay);
  3990. }
  3991.  
  3992. //If you want to show a string depending on if you have a certain item or not
  3993. if ((item_id > 0))
  3994. {
  3995. //If you do not have a certain item
  3996. if (!Link->Item[item_id])
  3997. {
  3998. //Show the first string on the screen
  3999. Screen->Message(string);
  4000. }
  4001.  
  4002. //If you do have that item
  4003. else if(Link->Item[item_id])
  4004. {
  4005. //Show the second string on the screen
  4006. Screen->Message(string2);
  4007. }
  4008. }
  4009.  
  4010. else
  4011. {
  4012. //This runs the first time you enter the screen
  4013. if (Screen->D[screen_var] != screen_check)
  4014. {
  4015. //Show the first string on the screen
  4016. Screen->Message(string);
  4017.  
  4018. //If you have chosen to use a second string
  4019. if (string2 > 0)
  4020. {
  4021. //Set Screen->D[screen_var] to be equal to screen_check(1)
  4022. Screen->D[screen_var] = screen_check;
  4023. }
  4024. }
  4025.  
  4026. //This runs if you have chosen to use a second string,
  4027. //and you have already visited the screen once before
  4028. else
  4029. {
  4030. //Show the second string on the screen
  4031. Screen->Message(string2);
  4032.  
  4033. //If you want to toggle between string1 and string2 every time you enter the screen
  4034. if (toggle > 0)
  4035. {
  4036. //Now Zelda Classic will think that you have never visited the screen before :)
  4037. //(Seriously, this just changes the Screen->D[screen_var] variable to the default value)
  4038. Screen->D[screen_var] = 0;
  4039. }
  4040. }
  4041.  
  4042. //This only runs if you have set D2(no_return) to 1 or more
  4043. if (no_return > 0)
  4044. {
  4045. //Set Screen->D[screen_var] to be equal to screen_check(1)
  4046. Screen->D[screen_var] = screen_check;
  4047. }
  4048. }
  4049. }
  4050. }
  4051.  
  4052. const int COMPASS_BEEP = 7; //Set this to the SFX id you want to hear when you have the compass,
  4053.  
  4054. //Instructions:
  4055. //1.- Compile and add this to your ZQuest buffer.
  4056. //2.- Add an FFC with this script attached to the screen where you want to hear the compass beep.
  4057. //3.- Let the script do the rest.
  4058.  
  4059. //How does it work:
  4060. //The script checks if ANY of the following has been done:
  4061. //a) Item or Special Item has been picked up.
  4062. //b) Any type of chest has been opened.
  4063. //c) If NOTHING of the above has been done, the script runs. Otherwise, no SFX is heard.
  4064.  
  4065. ffc script CompassBeep{
  4066. void run(){
  4067. if(!Screen->State[ST_ITEM] &&
  4068. !Screen->State[ST_CHEST] &&
  4069. !Screen->State[ST_LOCKEDCHEST] &&
  4070. !Screen->State[ST_BOSSCHEST] &&
  4071. !Screen->State[ST_SPECIALITEM] && (Game->LItems[Game->GetCurLevel()] & LI_COMPASS)){
  4072. Game->PlaySound(COMPASS_BEEP);
  4073. }
  4074. }
  4075. }
  4076.  
  4077. ffc script SpinAttackCheck{
  4078. void run(int sfx){
  4079. if ( Screen->State[ST_SECRET] )
  4080. Quit();
  4081. bool spin;
  4082. while(true){
  4083. if ( Link->Action == LA_SPINNING )
  4084. spin = true;
  4085. if ( !Link->Action == LA_SPINNING && spin ) {
  4086. if ( sfx == 0 )
  4087. Game->PlaySound(27);
  4088. if ( sfx > 0 )
  4089. Game->PlaySound(sfx);
  4090. Screen->TriggerSecrets();
  4091. Screen->State[ST_SECRET] = true;
  4092. Quit();
  4093. }
  4094. Waitframe();
  4095. }
  4096. }
  4097. }
  4098.  
  4099. const int SFX_SWITCH_PRESS = 67; //SFX when a switch is pressed
  4100. const int SFX_SWITCH_RELEASE = 67; //SFX when a switch is released
  4101. const int SFX_SWITCH_ERROR = 68; //SFX when the wrong switch is pressed
  4102.  
  4103. int Switch_Pressed(int x, int y){
  4104. int xOff = 0;
  4105. int yOff = 4;
  4106. int xDist = 8;
  4107. int yDist = 8;
  4108. if(Abs(Link->X+xOff-x)<=xDist&&Abs(Link->Y+yOff-y)<=yDist)
  4109. return 1;
  4110. if(Screen->MovingBlockX>-1){
  4111. if(Abs(Screen->MovingBlockX-x)<=8&&Abs(Screen->MovingBlockY-y)<=8)
  4112. return 1;
  4113. }
  4114. if(Screen->isSolid(x+4, y+4)||
  4115. Screen->isSolid(x+12, y+4)||
  4116. Screen->isSolid(x+4, y+12)||
  4117. Screen->isSolid(x+12, y+12)){
  4118. return 2;
  4119. }
  4120. return 0;
  4121. }
  4122.  
  4123. ffc script Switch_Secret{
  4124. void run(int perm, int id, int sfx){
  4125. int d;
  4126. int db;
  4127. if(id>0){
  4128. d = Floor((id-1)/16);
  4129. db = 1<<((id-1)%16);
  4130. }
  4131. if(perm){
  4132. if(id>0){
  4133. if(Screen->D[d]&db){
  4134. this->Data++;
  4135. Screen->TriggerSecrets();
  4136. Quit();
  4137. }
  4138. }
  4139. else if(Screen->State[ST_SECRET]){
  4140. this->Data++;
  4141. Quit();
  4142. }
  4143. }
  4144. while(!Switch_Pressed(this->X, this->Y)){
  4145. Waitframe();
  4146. }
  4147. this->Data++;
  4148. Screen->TriggerSecrets();
  4149. Game->PlaySound(SFX_SWITCH_PRESS);
  4150. if(sfx==0)
  4151. Game->PlaySound(SFX_SECRET);
  4152. else if(sfx>0)
  4153. Game->PlaySound(sfx);
  4154. if(perm){
  4155. if(id>0)
  4156. Screen->D[d]|=db;
  4157. else
  4158. Screen->State[ST_SECRET] = true;
  4159. }
  4160. }
  4161. }
  4162.  
  4163. ffc script Switch_Remote{
  4164. void run(int pressure, int id, int flag, int sfx){
  4165. int data = this->Data;
  4166. int i; int j; int k;
  4167. int d;
  4168. int db;
  4169. if(id>0){
  4170. d = Floor((id-1)/16);
  4171. db = 1<<((id-1)%16);
  4172. }
  4173. int comboD[176];
  4174. for(i=0; i<176; i++){
  4175. if(Screen->ComboF[i]==flag){
  4176. comboD[i] = Screen->ComboD[i];
  4177. Screen->ComboF[i] = 0;
  4178. }
  4179. }
  4180. if(id>0){
  4181. if(Screen->D[d]&db){
  4182. this->Data = data+1;
  4183. for(i=0; i<176; i++){
  4184. if(comboD[i]>0){
  4185. Screen->ComboD[i] = comboD[i]+1;
  4186. }
  4187. }
  4188. Quit();
  4189. }
  4190. }
  4191. if(pressure){
  4192. while(true){
  4193. while(!Switch_Pressed(this->X, this->Y)){
  4194. Waitframe();
  4195. }
  4196. this->Data = data+1;
  4197. Game->PlaySound(SFX_SWITCH_PRESS);
  4198. for(i=0; i<176; i++){
  4199. if(comboD[i]>0){
  4200. Screen->ComboD[i] = comboD[i]+1;
  4201. }
  4202. }
  4203. while(Switch_Pressed(this->X, this->Y)){
  4204. Waitframe();
  4205. }
  4206. this->Data = data;
  4207. Game->PlaySound(SFX_SWITCH_RELEASE);
  4208. for(i=0; i<176; i++){
  4209. if(comboD[i]>0){
  4210. Screen->ComboD[i] = comboD[i];
  4211. }
  4212. }
  4213. }
  4214. }
  4215. else{
  4216. while(!Switch_Pressed(this->X, this->Y)){
  4217. Waitframe();
  4218. }
  4219. this->Data = data+1;
  4220. Game->PlaySound(SFX_SWITCH_PRESS);
  4221. if(sfx>0)
  4222. Game->PlaySound(sfx);
  4223. else
  4224. Game->PlaySound(SFX_SECRET);
  4225. for(i=0; i<176; i++){
  4226. if(comboD[i]>0){
  4227. Screen->ComboD[i] = comboD[i]+1;
  4228. }
  4229. }
  4230. if(id>0){
  4231. Screen->D[d] |= db;
  4232. }
  4233. }
  4234. }
  4235. }
  4236.  
  4237. ffc script Switch_HitAll{
  4238. void run(int switchCmb, int pressure, int perm, int id, int flag, int sfx, int switchID){
  4239. int i; int j; int k;
  4240. int d;
  4241. int db;
  4242. if(flag==0)
  4243. id = 0;
  4244. int comboD[176];
  4245. if(id>0){
  4246. d = Floor((id-1)/16);
  4247. db = 1<<((id-1)%16);
  4248. for(i=0; i<176; i++){
  4249. if(Screen->ComboF[i]==flag){
  4250. comboD[i] = Screen->ComboD[i];
  4251. Screen->ComboF[i] = 0;
  4252. }
  4253. }
  4254. }
  4255. int switches[34];
  4256. int switchD[34];
  4257. int switchDB[34];
  4258. switchD[0] = switchID;
  4259. bool switchesPressed[34];
  4260. k = SizeOfArray(switches)-2;
  4261. for(i=0; i<176&&switches[0]<k; i++){
  4262. if(Screen->ComboD[i]==switchCmb){
  4263. j = 2+switches[0];
  4264. switches[j] = i;
  4265. if(!pressure&&switchID>0){
  4266. switchD[j] = Floor((switchID+switches[0]-1)/16);
  4267. switchDB[j] = 1<<((switchID+switches[0]-1)%16);
  4268. if(Screen->D[switchD[j]]&switchDB[j]){
  4269. switchesPressed[j] = true;
  4270. Screen->ComboD[i] = switchCmb+1;
  4271. switches[1]++;
  4272. }
  4273. }
  4274. switches[0]++;
  4275. }
  4276. }
  4277. if(perm){
  4278. if(id>0){
  4279. if(Screen->D[d]&db){
  4280. for(i=2; i<switches[0]+2; i++){
  4281. Screen->ComboD[switches[i]] = switchCmb+1;
  4282. switchesPressed[i] = true;
  4283. }
  4284. for(i=0; i<176; i++){
  4285. if(comboD[i]>0){
  4286. Screen->ComboD[i] = comboD[i]+1;
  4287. }
  4288. }
  4289. while(true){
  4290. Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
  4291. Waitframe();
  4292. }
  4293. }
  4294. }
  4295. if(Screen->State[ST_SECRET]){
  4296. for(i=2; i<switches[0]+2; i++){
  4297. Screen->ComboD[switches[i]] = switchCmb+1;
  4298. switchesPressed[i] = true;
  4299. }
  4300. while(true){
  4301. Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
  4302. Waitframe();
  4303. }
  4304. }
  4305. }
  4306. if(pressure){
  4307. while(switches[1]<switches[0]){
  4308. Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, true);
  4309. Waitframe();
  4310. }
  4311. if(id>0){
  4312. if(sfx>0)
  4313. Game->PlaySound(sfx);
  4314. else
  4315. Game->PlaySound(SFX_SECRET);
  4316. for(i=0; i<176; i++){
  4317. if(comboD[i]>0){
  4318. Screen->ComboD[i] = comboD[i]+1;
  4319. }
  4320. }
  4321. }
  4322. else{
  4323. if(sfx>0)
  4324. Game->PlaySound(sfx);
  4325. else
  4326. Game->PlaySound(SFX_SECRET);
  4327. Screen->TriggerSecrets();
  4328. }
  4329. if(perm){
  4330. if(id>0)
  4331. Screen->D[d] |= db;
  4332. else
  4333. Screen->State[ST_SECRET] = true;
  4334. }
  4335. }
  4336. else{
  4337. while(switches[1]<switches[0]){
  4338. Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
  4339. Waitframe();
  4340. }
  4341. if(id>0){
  4342. if(sfx>0)
  4343. Game->PlaySound(sfx);
  4344. else
  4345. Game->PlaySound(SFX_SECRET);
  4346. for(i=0; i<176; i++){
  4347. if(comboD[i]>0){
  4348. Screen->ComboD[i] = comboD[i]+1;
  4349. }
  4350. }
  4351. }
  4352. else{
  4353. if(sfx>0)
  4354. Game->PlaySound(sfx);
  4355. else
  4356. Game->PlaySound(SFX_SECRET);
  4357. Screen->TriggerSecrets();
  4358. }
  4359. if(perm){
  4360. if(id>0)
  4361. Screen->D[d] |= db;
  4362. else
  4363. Screen->State[ST_SECRET] = true;
  4364. }
  4365. }
  4366. while(true){
  4367. Switches_Update(switches, switchD, switchDB, switchesPressed, switchCmb, false);
  4368. Waitframe();
  4369. }
  4370. }
  4371. void Switches_Update(int switches, int switchD, int switchDB, bool switchesPressed, int switchCmb, bool pressure){
  4372. if(pressure)
  4373. switches[1] = 0;
  4374. for(int i=0; i<switches[0]; i++){
  4375. int j = i+2;
  4376. int k = switches[j];
  4377. int p = Switch_Pressed(ComboX(k), ComboY(k));
  4378. if(p){
  4379. if(p!=2)
  4380. Screen->ComboD[k] = switchCmb+1;
  4381. if(!switchesPressed[j]){
  4382. Game->PlaySound(SFX_SWITCH_PRESS);
  4383. if(switchD[0]>0){
  4384. Screen->D[switchD[j]] |= switchDB[j];
  4385. }
  4386. switchesPressed[j] = true;
  4387. if(!pressure)
  4388. switches[1]++;
  4389. }
  4390. if(pressure)
  4391. switches[1]++;
  4392. }
  4393. else{
  4394. if(switchesPressed[j]){
  4395. if(pressure){
  4396. Game->PlaySound(SFX_SWITCH_RELEASE);
  4397. Screen->ComboD[k] = switchCmb;
  4398. switchesPressed[j] = false;
  4399. }
  4400. else{
  4401. if(Screen->ComboD[k]!=switchCmb+1)
  4402. Screen->ComboD[k] = switchCmb+1;
  4403. }
  4404. }
  4405. }
  4406. }
  4407. }
  4408. }
  4409.  
  4410. ffc script Switch_Trap{
  4411. void run(int enemyid, int count){
  4412. while(!Switch_Pressed(this->X, this->Y)){
  4413. Waitframe();
  4414. }
  4415. this->Data++;
  4416. Game->PlaySound(SFX_SWITCH_PRESS);
  4417. Game->PlaySound(SFX_SWITCH_ERROR);
  4418. for(int i=0; i<count; i++){
  4419. int pos = Switch_GetSpawnPos();
  4420. npc n = CreateNPCAt(enemyid, ComboX(pos), ComboY(pos));
  4421. Game->PlaySound(SFX_FALL);
  4422. n->Z = 176;
  4423. Waitframes(20);
  4424. }
  4425. }
  4426. int Switch_GetSpawnPos(){
  4427. int pos;
  4428. bool invalid = true;
  4429. int failSafe = 0;
  4430. while(invalid&&failSafe<512){
  4431. pos = Rand(176);
  4432. if(Switch_ValidSpawn(pos))
  4433. return pos;
  4434. }
  4435. for(int i=0; i<176; i++){
  4436. pos = i;
  4437. if(Switch_ValidSpawn(pos))
  4438. return pos;
  4439. }
  4440. }
  4441. bool Switch_ValidSpawn(int pos){
  4442. int x = ComboX(pos);
  4443. int y = ComboY(pos);
  4444. if(Screen->isSolid(x+4, y+4)||
  4445. Screen->isSolid(x+12, y+4)||
  4446. Screen->isSolid(x+4, y+12)||
  4447. Screen->isSolid(x+12, y+12)){
  4448. return false;
  4449.  
  4450. }
  4451. if(ComboFI(pos, CF_NOENEMY)||ComboFI(pos, CF_NOGROUNDENEMY))
  4452. return false;
  4453. int ct = Screen->ComboT[pos];
  4454. if(ct==CT_NOENEMY||ct==CT_NOGROUNDENEMY||ct==CT_NOJUMPZONE)
  4455. return false;
  4456. if(ct==CT_WATER||ct==CT_LADDERONLY||ct==CT_HOOKSHOTONLY||ct==CT_LADDERHOOKSHOT)
  4457. return false;
  4458. if(ct==CT_PIT||ct==CT_PITB||ct==CT_PITC||ct==CT_PITD||ct==CT_PITR)
  4459. return false;
  4460. return true;
  4461. }
  4462. }
  4463.  
  4464. ffc script Switch_Sequential{
  4465. void run(int flag, int perm, int sfx){
  4466. int i; int j; int k;
  4467. int switches[34];
  4468. int switchCmb[34];
  4469. int switchMisc[8];
  4470. bool switchesPressed[34];
  4471. k = SizeOfArray(switches)-2;
  4472. for(i=0; i<176&&switches[0]<k; i++){
  4473. if(Screen->ComboF[i]==flag){
  4474. j = 2+switches[0];
  4475. switches[j] = i;
  4476. switchCmb[j] = Screen->ComboD[i];
  4477. switches[0]++;
  4478. }
  4479. }
  4480. int switchOrder[34];
  4481. Switches_Organize(switches, switchOrder);
  4482. if(perm&&Screen->State[ST_SECRET]){
  4483. for(i=0; i<switches[0]; i++){
  4484. switchesPressed[i+2] = true;
  4485. }
  4486. while(true){
  4487. Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
  4488. Waitframe();
  4489. }
  4490. }
  4491. while(switches[1]<switches[0]){
  4492. Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, true);
  4493. if(switchMisc[0]==1){
  4494. switchMisc[0] = 0;
  4495. for(i=0; i<30; i++){
  4496. Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
  4497. Waitframe();
  4498. }
  4499. while(Switches_LinkOn(switches)){
  4500. Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
  4501. Waitframe();
  4502. }
  4503. }
  4504. Waitframe();
  4505. }
  4506. if(sfx>0)
  4507. Game->PlaySound(sfx);
  4508. else
  4509. Game->PlaySound(SFX_SECRET);
  4510. Screen->TriggerSecrets();
  4511. if(perm)
  4512. Screen->State[ST_SECRET] = true;
  4513. for(i=0; i<switches[0]; i++){
  4514. switchesPressed[i+2] = true;
  4515. }
  4516. while(true){
  4517. Switches_Update(switches, switchesPressed, switchOrder, switchCmb, switchMisc, false);
  4518. Waitframe();
  4519. }
  4520.  
  4521. }
  4522. void Switches_Organize(int switches, int switchOrder){
  4523. bool banned[34];
  4524. for(int j=0; j<switches[0]; j++){
  4525. int lowest = -1;
  4526. int lowestIndex = -1;
  4527. for(int i=0; i<switches[0]; i++){
  4528. int c = Screen->ComboD[switches[i+2]];
  4529. if(c!=-1&&!banned[i+2]){
  4530. if(lowest==-1||c<lowest){
  4531. lowest = c;
  4532. lowestIndex = i+2;
  4533. }
  4534. }
  4535. }
  4536. switchOrder[j] = lowestIndex;
  4537. banned[lowestIndex] = true;
  4538. }
  4539. }
  4540. bool Switches_LinkOn(int switches){
  4541. for(int i=0; i<switches[0]; i++){
  4542. int j = i+2;
  4543. int k = switches[j];
  4544. int p = Switch_Pressed(ComboX(k), ComboY(k));
  4545. if(p==1)
  4546. return true;
  4547. }
  4548. return false;
  4549. }
  4550. void Switches_Update(int switches, bool switchesPressed, int switchOrder, int switchCmb, int switchMisc, bool canPress){
  4551. bool reset;
  4552. for(int i=0; i<switches[0]; i++){
  4553. int j = i+2;
  4554. int k = switches[j];
  4555. int p = Switch_Pressed(ComboX(k), ComboY(k));
  4556. if(!switchesPressed[j]){
  4557. if(p!=2)
  4558. Screen->ComboD[k] = switchCmb[j];
  4559. if(p&&canPress){
  4560. if(j==switchOrder[switches[1]]){
  4561. switches[1]++;
  4562. Game->PlaySound(SFX_SWITCH_PRESS);
  4563. switchesPressed[j] = true;
  4564. }
  4565. else{
  4566. switches[1] = 0;
  4567. Game->PlaySound(SFX_SWITCH_ERROR);
  4568. reset = true;
  4569. }
  4570. }
  4571. }
  4572. else{
  4573. if(p!=2)
  4574. Screen->ComboD[k] = switchCmb[j]+1;
  4575. if(p==0&&canPress){
  4576. Game->PlaySound(SFX_SWITCH_RELEASE);
  4577. switchesPressed[j] = false;
  4578. }
  4579. }
  4580. }
  4581. if(reset){
  4582. switchMisc[0] = 1;
  4583. for(int i=0; i<switches[0]; i++){
  4584. int j = i+2;
  4585. int k = switches[j];
  4586. int p = Switch_Pressed(ComboX(k), ComboY(k));
  4587. switchesPressed[j] = false;
  4588. }
  4589. }
  4590. }
  4591. }
  4592.  
  4593. // Edit the following constants according to your tileset.
  4594.  
  4595. // All combos between and including these two values will be considered regular diggable combos.
  4596. // The combo dug by the player will change, and there will be a chance for an item drop.
  4597. const int DigComboStart=3266;
  4598. const int DigComboEnd=3273;
  4599.  
  4600. // The following combos are similarly diggable, but turn into a different kind of combo and
  4601. // do not give item drops. You can use this to have secret stairs, for example.
  4602. // Important: Make sure these combos directly follow the DigComboEnd one.
  4603. const int DigSpecialStart=3274;
  4604. const int DigSpecialEnd=3277;
  4605.  
  4606. // A regular diggable combo will turn into this combo when you use the shovel on it.
  4607. const int DugComboNormal=3278;
  4608.  
  4609. // A special combo will turn into this combo when you use the shovel on it.
  4610. // You can, for example, make it a tile warp, so the player can dig for secret entrances.
  4611. // Set up the warps and the arrival points on your ZQuest screen as usual.
  4612. const int DugComboSpecial=3279;
  4613.  
  4614. // This is the sound to be played when you successfully dig.
  4615. const int ShovelSound=4;
  4616. // The sound to be played when you attempt to dig an undiggable combo.
  4617. const int ShovelFail=51;
  4618. // The secret sound to be played when you dig a special combo.
  4619. const int SecretSound=25;
  4620.  
  4621. item script Shovel{
  4622. void run(){
  4623. int chance;
  4624. int itemdrop;
  4625. int itemlocx;
  4626. int itemlocy;
  4627. Link->Action=LA_ATTACKING;
  4628. if((Link->Dir==0&&(Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]<DigComboStart||Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]>DigSpecialEnd))
  4629. ||(Link->Dir==1&&(Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]<DigComboStart||Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]>DigSpecialEnd))
  4630. ||(Link->Dir==2&&(Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]<DigComboStart||Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]>DigSpecialEnd))
  4631. ||(Link->Dir==3&&(Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]<DigComboStart||Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]>DigSpecialEnd))){
  4632. Game->PlaySound(ShovelFail);
  4633. }
  4634. else{
  4635. Game->PlaySound(ShovelSound);
  4636. chance=Rand(100)+1;
  4637. if(Link->Dir==0){
  4638. if(Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]<DigSpecialStart){
  4639. Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]=DugComboNormal;
  4640. }
  4641. else{
  4642. Game->PlaySound(SecretSound);
  4643. Screen->ComboD[ComboAt(Link->X+8,Link->Y-8)]=DugComboSpecial;
  4644. chance=101;
  4645. }
  4646. }
  4647. if(Link->Dir==1){
  4648. if(Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]<DigSpecialStart){
  4649. Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]=DugComboNormal;
  4650. }
  4651. else{
  4652. Game->PlaySound(SecretSound);
  4653. Screen->ComboD[ComboAt(Link->X+8,Link->Y+24)]=DugComboSpecial;
  4654. chance=101;
  4655. }
  4656. }
  4657. if(Link->Dir==2){
  4658. if(Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]<DigSpecialStart){
  4659. Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]=DugComboNormal;
  4660. }
  4661. else{
  4662. Game->PlaySound(SecretSound);
  4663. Screen->ComboD[ComboAt(Link->X-8,Link->Y+8)]=DugComboSpecial;
  4664. chance=101;
  4665. }
  4666. }
  4667. if(Link->Dir==3){
  4668. if(Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]<DigSpecialStart){
  4669. Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]=DugComboNormal;
  4670. }
  4671. else{
  4672. Game->PlaySound(SecretSound);
  4673. Screen->ComboD[ComboAt(Link->X+24,Link->Y+8)]=DugComboSpecial;
  4674. chance=101;
  4675. }
  4676. }
  4677. // The item drops are currently set to be the same as the default tall grass combo drops.
  4678. // The variable "chance" is a randomly generated number between 1 and 100.
  4679. // It determines whether you will get an item, and if so, which one.
  4680. // Here, you have a 20% chance to spawn 1 rupee, and a 15% chance to spawn a heart.
  4681. // If you want, edit this or add more lines to spawn more drops.
  4682. // You can use this line as a template: if(chance>=21&&chance<=35)itemdrop=2;
  4683. // The "chance" variable determines the chance you have of obtaining the item, as we've
  4684. // seen before, and the "itemdrop" variable is the number of the item in ZQuest.
  4685. if(chance<=20)itemdrop=0;
  4686. if(chance>=21&&chance<=35)itemdrop=2;
  4687. // NB: If you dug a special combo, the "chance" variable is automatically set to 101 so
  4688. // the script won't spawn drops on top of special combos like stairs.
  4689. if(Link->Dir==0){
  4690. itemlocx=Link->X;
  4691. itemlocy=Link->Y-16;
  4692. }
  4693. if(Link->Dir==1){
  4694. itemlocx=Link->X;
  4695. itemlocy=Link->Y+16;
  4696. }
  4697. if(Link->Dir==2){
  4698. itemlocx=Link->X-16;
  4699. itemlocy=Link->Y;
  4700. }
  4701. if(Link->Dir==3){
  4702. itemlocx=Link->X+16;
  4703. itemlocy=Link->Y;
  4704. }
  4705. // This is the part of the code that spawns the item.
  4706. // If you have edited the default item drops, change "35" and set it according to your drops.
  4707. if(chance<=35){
  4708. item i=Screen->CreateItem(itemdrop);
  4709. i->X=itemlocx;
  4710. i->Y=itemlocy;
  4711. i->Z=10;
  4712. i->Pickup=IP_TIMEOUT;
  4713. }
  4714. }
  4715. }
  4716. }
  4717.  
  4718. //D0: ID of the item
  4719. //D1: Price of the item
  4720. //D2: Message that plays when the item is bought
  4721. //D3: Message that plays when you don't have enough rupees
  4722. //D4: Input type 0=A 1=B 2=L 3=R
  4723.  
  4724. ffc script SimpleShop{
  4725. void run(int itemID, int price, int m, int n, int input){
  4726. int loc = ComboAt(this->X,this->Y);
  4727. while(true){
  4728. while(!AgainstComboBase(loc) || !SelectPressInput(input)) Waitframe();
  4729. SetInput(input,false);
  4730. if(Game->Counter[CR_RUPEES] >= price){
  4731. Game->DCounter[CR_RUPEES] -= price;
  4732. item shpitm = CreateItemAt(itemID, Link->X, Link->Y);
  4733. shpitm->Pickup = IP_HOLDUP;
  4734. Screen->Message(m);
  4735. }
  4736. else{
  4737. Screen->Message(n);
  4738. }
  4739. Waitframe();
  4740. }
  4741. }
  4742. bool AgainstComboBase(int loc){
  4743. return Link->Z == 0 && (Link->Dir == DIR_UP && Link->Y == ComboY(loc)+8 && Abs(Link->X-ComboX(loc)) < 8);
  4744. }
  4745. }
  4746.  
  4747.  
  4748. ffc script Signpost{
  4749. void run(int m,int input){
  4750. int loc = ComboAt(this->X,this->Y);
  4751. while(true){
  4752. while(!AgainstComboBase(loc) || !SelectPressInput(input)) Waitframe();
  4753. SetInput(input,false);
  4754. Screen->Message(m);
  4755. Waitframe();
  4756. }
  4757. }
  4758. bool AgainstComboBase(int loc){
  4759. return Link->Z == 0 && (Link->Dir == DIR_UP && Link->Y == ComboY(loc)+8 && Abs(Link->X-ComboX(loc)) < 8);
  4760. }
  4761. }
  4762.  
  4763. ffc script ButtonDisabler
  4764. {
  4765. void run()
  4766. {
  4767.  
  4768. while(true)
  4769. {
  4770. Game->SkipF6 = true;
  4771. Link->InputStart = false; Link->PressStart = false;
  4772. Link->InputMap = false; Link->PressMap = false;
  4773. NoAction();
  4774. Waitframe();
  4775. }
  4776. }
  4777. }
  4778.  
  4779. //Instructions:
  4780. //1. Make a new combo with inherent flag 16 (or any secret flag)
  4781. //2. Set this FFC to the above combo
  4782. //3. When secrets are triggered by blocks, this script will make it permanent
  4783. ffc script blockPermSecrets{
  4784. void run(){
  4785. int thisCombo = this->Data;
  4786. while(!Screen->State[ST_SECRET]){
  4787. if(this->Data != thisCombo) Screen->State[ST_SECRET] = true;
  4788. Waitframe();
  4789. }
  4790. }
  4791. }
  4792.  
  4793. screendata script ChangeEnemies
  4794. {
  4795. void run(int changeItem, int e1, int e2, int e3, int ne1, int ne2, int ne3)
  4796. {
  4797. unless(Hero->Item[changeItem]) Quit();
  4798. for(int q = 0; q < 10; ++q)
  4799. {
  4800. if(Screen->Enemy[q] == e1)
  4801. Screen->Enemy[q] = ne1;
  4802. else if(Screen->Enemy[q] == e2)
  4803. Screen->Enemy[q] = ne2;
  4804. else if(Screen->Enemy[q] == e3)
  4805. Screen->Enemy[q] = ne3;
  4806. }
  4807. }
  4808. }
  4809.  
  4810. ffc script NewScreenChanger
  4811. {
  4812. void run(int changeItem, int e1, int e2, int e3, int ne1, int ne2, int ne3)
  4813. {
  4814. unless(Hero->Item[changeItem]) Quit();
  4815. for(int q = 0; q < 10; ++q)
  4816. {
  4817. if(Screen->Enemy[q] == e1)
  4818. Screen->Enemy[q] = ne1;
  4819. else if(Screen->Enemy[q] == e2)
  4820. Screen->Enemy[q] = ne2;
  4821. else if(Screen->Enemy[q] == e3)
  4822. Screen->Enemy[q] = ne3;
  4823. }
  4824. }
  4825. }
  4826.  
  4827. const int SAGESSTONE_SOUND = 136; //Set this to the SFX id you want to hear when you have the compass,
  4828.  
  4829. //Instructions:
  4830. //1.- Compile and add this to your ZQuest buffer.
  4831. //2.- Add an FFC with this script attached to the screen where you want to hear the compass beep.
  4832. //3.- Let the script do the rest.
  4833.  
  4834. //How does it work:
  4835. //The script checks if ANY of the following has been done:
  4836. //a) Item or Special Item has been picked up.
  4837. //b) Any type of chest has been opened.
  4838. //c) If NOTHING of the above has been done, the script runs. Otherwise, no SFX is heard.
  4839.  
  4840. ffc script StonesOfSages{
  4841. void run(){
  4842. if(!Screen->State[ST_ITEM] &&
  4843. !Screen->State[ST_CHEST] &&
  4844. !Screen->State[ST_LOCKEDCHEST] &&
  4845. !Screen->State[ST_BOSSCHEST] &&
  4846. !Screen->State[ST_SPECIALITEM] && (Game->LItems[Game->GetCurLevel()] & LI_COMPASS)){
  4847. Game->PlaySound(SAGESSTONE_SOUND);
  4848. }
  4849. }
  4850. }
  4851.  
  4852. screendata script ChangeEnemiesAndMidi
  4853. {
  4854. void run(int changeItem, int e1, int e2, int e3, int ne1, int ne2, int ne3, int midi)
  4855. {
  4856. unless(Hero->Item[changeItem]) Quit();
  4857. for(int q = 0; q < 10; ++q)
  4858. {
  4859. if(Screen->Enemy[q] == e1)
  4860. Screen->Enemy[q] = ne1;
  4861. else if(Screen->Enemy[q] == e2)
  4862. Screen->Enemy[q] = ne2;
  4863. else if(Screen->Enemy[q] == e3)
  4864. Screen->Enemy[q] = ne3;
  4865. }
  4866. unless(midi) return;
  4867. if(midi == -1)
  4868. {
  4869. midi = Game->LoadDMapData(Game->GetCurDMap())->MIDI;
  4870. }
  4871. Audio->PlayMIDI(midi);
  4872. }
  4873. }
  4874.  
  4875. item script FlareSwordItem{
  4876. void run(int nothing, int firesprite){
  4877. int name[] = "FlareSwordFFC";
  4878. int args[8];
  4879. args[0] = firesprite;
  4880. RunFFCScript(Game->GetFFCScript(name), args);
  4881. }
  4882. }
  4883.  
  4884. ffc script FlareSwordFFC
  4885. {void run(int firesprite)
  4886. {
  4887. int SwordX;
  4888. int SwordY;
  4889. int PreviousSwordX;
  4890. int PreviousSwordY;
  4891. int SwordDmg;
  4892. while(true){
  4893. SwordX = -1000;
  4894. SwordY = -1000;
  4895. for (int i = Screen->NumLWeapons(); i > 0; i--) {
  4896. lweapon wpn = Screen->LoadLWeapon(i);
  4897. if ( wpn->ID == LW_SWORD ) {
  4898. SwordX = wpn->X;
  4899. SwordY = wpn->Y;
  4900. SwordDmg = wpn->Damage;
  4901. }
  4902. }
  4903. if ( SwordX == -1000 && SwordY == -1000 )
  4904. Quit();
  4905. if ( Link->Action != LA_CHARGING && Link->Action != LA_GOTHURTLAND && (SwordX != PreviousSwordX || SwordY != PreviousSwordY) ) {
  4906. Game->PlaySound(13);
  4907. lweapon wpn = CreateLWeaponAt(LW_FIRE, SwordX, SwordY);
  4908. wpn->UseSprite(firesprite);
  4909. wpn->Damage = SwordDmg;
  4910. wpn->Step = 0;
  4911. }
  4912. PreviousSwordX = SwordX;
  4913. PreviousSwordY = SwordY;
  4914. Waitframe();
  4915. }
  4916. }
  4917. }
  4918.  
  4919. itemsprite script FlareSwordSprite
  4920. {void run(int firesprite)
  4921. {
  4922. int SwordX;
  4923. int SwordY;
  4924. int PreviousSwordX;
  4925. int PreviousSwordY;
  4926. int SwordDmg;
  4927. while(true){
  4928. SwordX = -1000;
  4929. SwordY = -1000;
  4930. for (int i = Screen->NumLWeapons(); i > 0; i--) {
  4931. lweapon wpn = Screen->LoadLWeapon(i);
  4932. if ( wpn->ID == LW_SWORD ) {
  4933. SwordX = wpn->X;
  4934. SwordY = wpn->Y;
  4935. SwordDmg = wpn->Damage;
  4936. }
  4937. }
  4938. if ( SwordX == -1000 && SwordY == -1000 )
  4939. Quit();
  4940. if ( Link->Action != LA_CHARGING && Link->Action != LA_GOTHURTLAND && (SwordX != PreviousSwordX || SwordY != PreviousSwordY) ) {
  4941. Game->PlaySound(13);
  4942. lweapon wpn = CreateLWeaponAt(LW_FIRE, SwordX, SwordY);
  4943. wpn->UseSprite(firesprite);
  4944. wpn->Damage = SwordDmg;
  4945. wpn->Step = 0;
  4946. }
  4947. PreviousSwordX = SwordX;
  4948. PreviousSwordY = SwordY;
  4949. Waitframe();
  4950. }
  4951. }
  4952. }
  4953.  
  4954. lweapon script FireRod
  4955. {
  4956. void run()
  4957. {
  4958. lweapon flame = Screen->CreateLWeapon(LW_FIRE);
  4959. while(this->isValid())
  4960. {
  4961. flame->X = this->X;
  4962. flame->Y = this->Y;
  4963. flame->Dir = this->Dir;
  4964. Waitframe();
  4965. }
  4966. }
  4967. }
  4968.  
  4969. lweapon script bombarrow
  4970. {
  4971. void run()
  4972. {
  4973.  
  4974. itemdata bomb; bool found; bool super; int x; int y; int pow;
  4975. bomb = Game->LoadItemData(Link->ItemA);
  4976. if ( bomb->Family == IC_BOMB ) found = true;
  4977. if ( bomb->Family == IC_SBOMB ) { found = true; super = true; }
  4978. if ( !found )
  4979. {
  4980. bomb = Game->LoadItemData(Link->ItemB);
  4981. if ( bomb->Family == IC_BOMB ) { found = true; }
  4982. if ( bomb->Family == IC_SBOMB ) { found = true; super = true; }
  4983. }
  4984. if ( !found ) Quit(); //quit if bombs not in a slot
  4985. else
  4986. {
  4987. pow = bomb->Power;
  4988. if ( super )
  4989. {
  4990. if ( !Game->Counter[CR_SBOMBS] ) Quit(); //quit if not enough bombs
  4991. else --Game->Counter[CR_SBOMBS];
  4992. }
  4993. else
  4994. {
  4995. if ( !Game->Counter[CR_BOMBS] ) Quit(); //quit if not enough bombs
  4996. else --Game->Counter[CR_BOMBS];
  4997. }
  4998. }
  4999.  
  5000.  
  5001. while(this->isValid())
  5002. {
  5003. x = this->X; y = this->Y;
  5004.  
  5005. if ( this->DeadState != WDS_ALIVE ) //When the arrow itself dies, make an explosion.
  5006. {
  5007. lweapon boom = Screen->CreateLWeapon( (( super ) ? LW_SBOMBBLAST : LW_BOMBBLAST ));
  5008. boom->Damage = pow;
  5009. boom->X = x;
  5010. boom->Y = y;
  5011. }
  5012.  
  5013. Waitframe();
  5014. }
  5015.  
  5016. }
  5017. }
  5018.  
  5019. eweapon script dairaaxe
  5020. {
  5021. void run()
  5022. {
  5023. this->X = Clamp(this->X, 1, 255);
  5024. this->Y = Clamp(this->Y, 1, 175);
  5025. int timer = 22;
  5026. while(this->isValid())
  5027. {
  5028. this->X = Clamp(this->X, 1, 255);
  5029. this->Y = Clamp(this->Y, 1, 175);
  5030. --timer;
  5031. if ( timer < 1 ) { Remove(this); Quit(); }
  5032. Waitframe();
  5033. }
  5034. }
  5035. }
  5036.  
  5037. const int RESET_NPC_LAYER_ON_ENTRY = 1; //This fix will replace all CMB_NPC_SOLID tiles with CMB_NPC_HIDDEN
  5038. //when entering the screen. This should prevent problems with shared
  5039. //layers. If you don't want this fix, set it to 0.
  5040.  
  5041. const int NPCSCRIPT_ITEMCHECK_ONLY_UPDATES_ON_SCREEN_ENTRY = 1; //Set to 1 if you want itemcheck NPCs to only disappear
  5042. //after you leave the screen.
  5043.  
  5044. const int NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH = 1; //This will make the script wait until a called script
  5045. //finishes before resuming, fixing issues where you talk
  5046. //to the NPC a second time while you should be frozen
  5047.  
  5048. const int LAYER_NPC = 1; //The layer NPCs use for solid combos
  5049. const int CMB_NPC_HIDDEN = 0; //Non-solid combo used for hidden NPCs
  5050. const int CMB_NPC_SOLID = 43; //Solid combo placed under visible NPCs
  5051.  
  5052. const int LAYER_NPC_CANTALK = 4; //The layer used for the speech bubble
  5053. const int CMB_NPC_CANTALK = 9059; //The combo used for the speech bubble
  5054. const int CS_NPC_CANTALK = 8; //The CSet used for the speech bubble
  5055.  
  5056. const int NPCBT_NONE = 0; //Regular NPCs
  5057. const int NPCBT_FACELINK = 1; //NPCs that turn to face Link
  5058. const int NPCBT_GUARDH = 2; //NPCs that move along a horizontal path
  5059. const int NPCBT_GUARDV = 3; //NPCs that move along a vertical path
  5060.  
  5061. ffc script NPCScript_Simple{
  5062. void run(int String, int Script, int D0, int D1, int D2, int D3, int D4, int D5){
  5063. //Saves the width and height of the FFC for collision checks
  5064. int Width = 16;
  5065. int Height = 16;
  5066. if(this->EffectWidth!=16)
  5067. Width = this->EffectWidth;
  5068. else if(this->TileWidth>1)
  5069. Width = this->TileWidth*16;
  5070. if(this->EffectHeight!=16)
  5071. Height = this->EffectHeight;
  5072. else if(this->TileHeight>1)
  5073. Height = this->TileHeight*16;
  5074. while(true){
  5075. //Facing Up
  5076. if(Link->Dir==DIR_UP&&Link->Y>=this->Y&&Link->Y<=this->Y+Height-8&&Link->X>=this->X-8&&Link->X<=this->X+Width-8){
  5077. if(CMB_NPC_CANTALK>0)
  5078. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5079. if(Link->PressA){
  5080. Link->InputA = false;
  5081. Link->PressA = false;
  5082. Screen->Message(String);
  5083. if(Script>0){
  5084. int Args[8] = {D0, D1, D2, D3, D4, D5};
  5085. RunFFCScript(Script, Args);
  5086. }
  5087. }
  5088. }
  5089. //Facing Down
  5090. else if(Link->Dir==DIR_DOWN&&Link->Y>=this->Y-16&&Link->Y<=this->Y+Height-16&&Link->X>=this->X-8&&Link->X<=this->X+Width-8){
  5091. if(CMB_NPC_CANTALK>0)
  5092. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5093. if(Link->PressA){
  5094. Link->InputA = false;
  5095. Link->PressA = false;
  5096. Screen->Message(String);
  5097. if(Script>0){
  5098. int Args[8] = {D0, D1, D2, D3, D4, D5};
  5099. RunFFCScript(Script, Args);
  5100. }
  5101. }
  5102. }
  5103. //Facing Left
  5104. else if(Link->Dir==DIR_LEFT&&Link->Y>=this->Y-8&&Link->Y<=this->Y+Height-8&&Link->X>=this->X&&Link->X<=this->X+Width){
  5105. if(CMB_NPC_CANTALK>0)
  5106. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5107. if(Link->PressA){
  5108. Link->InputA = false;
  5109. Link->PressA = false;
  5110. Screen->Message(String);
  5111. if(Script>0){
  5112. int Args[8] = {D0, D1, D2, D3, D4, D5};
  5113. RunFFCScript(Script, Args);
  5114. }
  5115. }
  5116. }
  5117. //Facing Right
  5118. else if(Link->Dir==DIR_RIGHT&&Link->Y>=this->Y-8&&Link->Y<=this->Y+Height-8&&Link->X>=this->X-16&&Link->X<=this->X+Width-16){
  5119. if(CMB_NPC_CANTALK>0)
  5120. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5121. if(Link->PressA){
  5122. Link->InputA = false;
  5123. Link->PressA = false;
  5124. Screen->Message(String);
  5125. if(Script>0){
  5126. int Args[8] = {D0, D1, D2, D3, D4, D5};
  5127. RunFFCScript(Script, Args);
  5128. }
  5129. }
  5130. }
  5131. Waitframe();
  5132. }
  5133. }
  5134. }
  5135.  
  5136. ffc script playsfx{
  5137. void run(int s, int wait, int r){
  5138. if (r == 0){
  5139. Waitframes(wait);
  5140. Game->PlaySound(s);
  5141. }
  5142. else{
  5143. while(true){
  5144. Waitframes(wait);
  5145. Game->PlaySound(s);
  5146. }
  5147. }
  5148. }
  5149. }
  5150.  
  5151. ffc script NPCScript{
  5152. void run(int String, int ItemCheck, int Type, int Arg1, int Arg2, int NoSolid, int Script, int ScriptArg){
  5153. //Stores the NPC's combo, hides it
  5154. int Combo = this->Data;
  5155. this->Data = CMB_NPC_HIDDEN;
  5156. //Waits until the NPC should appear and shows it
  5157. if(ItemCheck<0){
  5158. while(!Link->Item[Abs(ItemCheck)]){
  5159. Waitframe();
  5160. }
  5161. this->Data = Combo;
  5162. if(Type==NPCBT_FACELINK){
  5163. this->Data = Combo + Arg1;
  5164. }
  5165. }
  5166. else if(ItemCheck>0){
  5167. if(!Link->Item[Abs(ItemCheck)]){
  5168. this->Data = Combo;
  5169. if(Type==NPCBT_FACELINK){
  5170. this->Data = Combo + Arg1;
  5171. }
  5172. }
  5173. }
  5174. else if(ItemCheck==0){
  5175. this->Data = Combo;
  5176. if(Type==NPCBT_FACELINK){
  5177. this->Data = Combo + Arg1;
  5178. }
  5179. }
  5180. //Saves the width and height of the FFC for collision checks
  5181. int Width = 16;
  5182. int Height = 16;
  5183. if(this->EffectWidth!=16)
  5184. Width = this->EffectWidth;
  5185. else if(this->TileWidth>1)
  5186. Width = this->TileWidth*16;
  5187. if(this->EffectHeight!=16)
  5188. Height = this->EffectHeight;
  5189. else if(this->TileHeight>1)
  5190. Height = this->TileHeight*16;
  5191. //Wait until the screen is done scrolling to avoid a weird ZC crashing bug
  5192. Waitframe();
  5193. while(Link->Action==LA_SCROLLING){
  5194. Waitframe();
  5195. }
  5196. //Shared Layer Fix
  5197. if(RESET_NPC_LAYER_ON_ENTRY==1){
  5198. if(Screen->LoadFFC(FindFFCRunning(this->Script))==this){
  5199. for(int i=0; i<176; i++){
  5200. if(GetLayerComboD(LAYER_NPC, i)==CMB_NPC_SOLID){
  5201. SetLayerComboD(LAYER_NPC, i, CMB_NPC_HIDDEN);
  5202. }
  5203. }
  5204. }
  5205. }
  5206. //Sets the space below the NPC or the space a guard NPC occupies to be solid
  5207. if(LAYER_NPC>-1&&NoSolid==0){
  5208. if(Type==NPCBT_GUARDH){
  5209. for(int x=Arg1; x<=Arg2+this->TileWidth-1; x++){
  5210. for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
  5211. SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_SOLID);
  5212. }
  5213. }
  5214. }
  5215. else if(Type==NPCBT_GUARDV){
  5216. for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
  5217. for(int y=Arg1; y<=Arg2+this->TileHeight-1; y++){
  5218. SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_SOLID);
  5219. }
  5220. }
  5221. }
  5222. else{
  5223. for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
  5224. for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
  5225. SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_SOLID);
  5226. }
  5227. }
  5228. }
  5229. }
  5230. bool canItemCheck = true;
  5231. while(true){
  5232. //Prevent checking items past the first frame if the rule is checked
  5233. if(!NPCSCRIPT_ITEMCHECK_ONLY_UPDATES_ON_SCREEN_ENTRY)
  5234. canItemCheck = true;
  5235.  
  5236. //Removes NPCs if Link has the required item
  5237. if(ItemCheck>0&&canItemCheck){
  5238. if(Link->Item[ItemCheck]){
  5239. this->Data = CMB_NPC_HIDDEN;
  5240. if(LAYER_NPC>-1&&NoSolid==0){
  5241. if(Type==NPCBT_GUARDH){
  5242. for(int x=Arg1; x<=Arg2+this->TileWidth-1; x++){
  5243. for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
  5244. SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_HIDDEN);
  5245. }
  5246. }
  5247. }
  5248. else if(Type==NPCBT_GUARDV){
  5249. for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
  5250. for(int y=Arg1; y<=Arg2+this->TileHeight-1; y++){
  5251. SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_HIDDEN);
  5252. }
  5253. }
  5254. }
  5255. else{
  5256. for(int x=Floor(this->X/16); x<=Floor(this->X/16)+this->TileWidth-1; x++){
  5257. for(int y=Floor(this->Y/16); y<=Floor(this->Y/16)+this->TileHeight-1; y++){
  5258. SetLayerComboD(LAYER_NPC, y*16+x, CMB_NPC_HIDDEN);
  5259. }
  5260. }
  5261. }
  5262. }
  5263. Quit();
  5264. }
  5265. }
  5266.  
  5267. canItemCheck = false;
  5268.  
  5269. //Handles animation for turning NPCs
  5270. if(Type==NPCBT_FACELINK&&(Link->X>0&&Link->X<240&&Link->Y>0&&Link->Y<160)){
  5271. if(Distance(CenterLinkX(), CenterLinkY(), CenterX(this), CenterY(this))<Arg2)
  5272. this->Data = Combo + AngleDir4(Angle(CenterX(this), CenterY(this), CenterLinkX(), CenterLinkY()));
  5273. else
  5274. this->Data = Combo + Arg1;
  5275. }
  5276.  
  5277. //Handles movement for guard NPCs
  5278. else if(Type==NPCBT_GUARDH){
  5279. if(Link->X>16*Arg1-32&&Link->X<16*Arg2+32&&Link->Y>this->Y-32&&Link->Y<this->Y+32){
  5280. this->X = Clamp(this->X+(-this->X + Link->X)/4, 16*Arg1, 16*Arg2);
  5281. }
  5282. }
  5283. else if(Type==NPCBT_GUARDV){
  5284. if(Link->X>this->X-32&&Link->X<this->X+32&&Link->Y>16*Arg1-32&&Link->Y<16*Arg2+32){
  5285. this->Y = Clamp(this->Y+(-this->Y + Link->Y)/4, 16*Arg1, 16*Arg2);
  5286. }
  5287. }
  5288.  
  5289. int dialogueBox1[] = "DialogueBranch_Simple";
  5290. int dialogueBox2[] = "DialogueBranch_Advanced";
  5291. int scrDB1 = Game->GetFFCScript(dialogueBox1);
  5292. int scrDB2 = Game->GetFFCScript(dialogueBox2);
  5293.  
  5294.  
  5295. bool noTalk;
  5296. if(CountFFCsRunning(scrDB1)>0)
  5297. noTalk = true;
  5298. if(CountFFCsRunning(scrDB2)>0)
  5299. noTalk = true;
  5300.  
  5301. //Facing Up
  5302. if(!noTalk&&Link->Dir==DIR_UP&&Link->Y>=this->Y&&Link->Y<=this->Y+Height-8&&Link->X>=this->X-8&&Link->X<=this->X+Width-8){
  5303. if(CMB_NPC_CANTALK>0)
  5304. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5305. if(Link->PressA){
  5306. Link->InputA = false;
  5307. Link->PressA = false;
  5308. Screen->Message(String);
  5309. if(Script>0){
  5310. int args[8] = {ScriptArg};
  5311. int i = RunFFCScript(Script, args);
  5312. if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
  5313. ffc f = Screen->LoadFFC(i);
  5314. while(f->Script==Script){
  5315. Waitframe();
  5316. }
  5317. }
  5318. }
  5319. }
  5320. }
  5321. //Facing Down
  5322. else if(!noTalk&&Link->Dir==DIR_DOWN&&Link->Y>=this->Y-16&&Link->Y<=this->Y+Height-16&&Link->X>=this->X-8&&Link->X<=this->X+Width-8){
  5323. if(CMB_NPC_CANTALK>0)
  5324. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5325. if(Link->PressA){
  5326. Link->InputA = false;
  5327. Link->PressA = false;
  5328. Screen->Message(String);
  5329. if(Script>0){
  5330. int args[8] = {ScriptArg};
  5331. int i = RunFFCScript(Script, args);
  5332. if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
  5333. ffc f = Screen->LoadFFC(i);
  5334. while(f->Script==Script){
  5335. Waitframe();
  5336. }
  5337. }
  5338. }
  5339. }
  5340. }
  5341. //Facing Left
  5342. else if(!noTalk&&Link->Dir==DIR_LEFT&&Link->Y>=this->Y-8&&Link->Y<=this->Y+Height-8&&Link->X>=this->X&&Link->X<=this->X+Width){
  5343. if(CMB_NPC_CANTALK>0)
  5344. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5345. if(Link->PressA){
  5346. Link->InputA = false;
  5347. Link->PressA = false;
  5348. Screen->Message(String);
  5349. if(Script>0){
  5350. int args[8] = {ScriptArg};
  5351. int i = RunFFCScript(Script, args);
  5352. if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
  5353. ffc f = Screen->LoadFFC(i);
  5354. while(f->Script==Script){
  5355. Waitframe();
  5356. }
  5357. }
  5358. }
  5359. }
  5360. }
  5361. //Facing Right
  5362. else if(!noTalk&&Link->Dir==DIR_RIGHT&&Link->Y>=this->Y-8&&Link->Y<=this->Y+Height-8&&Link->X>=this->X-16&&Link->X<=this->X+Width-16){
  5363. if(CMB_NPC_CANTALK>0)
  5364. Screen->FastCombo(LAYER_NPC_CANTALK, Link->X, Link->Y-16, CMB_NPC_CANTALK, CS_NPC_CANTALK, 128);
  5365. if(Link->PressA){
  5366. Link->InputA = false;
  5367. Link->PressA = false;
  5368. Screen->Message(String);
  5369. if(Script>0){
  5370. int args[8] = {ScriptArg};
  5371. int i = RunFFCScript(Script, args);
  5372. if(NPCSCRIPT_WAITS_UNTIL_SCRIPTS_FINISH){
  5373. ffc f = Screen->LoadFFC(i);
  5374. while(f->Script==Script){
  5375. Waitframe();
  5376. }
  5377. }
  5378. }
  5379. }
  5380. }
  5381. Waitframe();
  5382. }
  5383. }
  5384. }
  5385.  
  5386. const int D_TRADE = 0; //Screen->D value used for the trade sequence state
  5387.  
  5388. ffc script TradeSequence{
  5389. void run(int CheckItem, int TradeItem, int NoItemString, int HasItemString, int TradedString){
  5390. //Check if the player has already traded
  5391. if(Screen->D[D_TRADE]==0){
  5392. //If player hasn't traded and has the required item, play HasItemString, give the new item, and take the old item
  5393. if(Link->Item[CheckItem]){
  5394. Screen->Message(HasItemString);
  5395. WaitNoAction();
  5396. item itm = CreateItemAt(TradeItem, Link->X, Link->Y);
  5397. itm->Pickup = IP_HOLDUP;
  5398. Link->Item[CheckItem] = false;
  5399. Screen->D[D_TRADE] = 1;
  5400. WaitNoAction();
  5401. }
  5402. //If player hasn't traded and doesn't have the required item, play NoItemString
  5403. else{
  5404. Screen->Message(NoItemString);
  5405. WaitNoAction();
  5406. }
  5407. }
  5408. //If the player has already traded, play TradedString
  5409. else{
  5410. Screen->Message(TradedString);
  5411. WaitNoAction();
  5412. }
  5413. }
  5414. }
  5415.  
  5416. const int CT_CLIFF = 142; //This is the combo type used for the cliffs. Look in std_constants.zh for reference. It's Script 1 (142) by default.
  5417. const int CLIFF_PAUSE = 15; //This is the number of frames (60ths of a second) Link must walk into the cliff before jumping
  5418.  
  5419. ffc script GBCliff{
  5420. bool CheckCliffDirection(int Combo){
  5421. int Dir;
  5422. if(Screen->ComboS[Combo]==0101b)
  5423. Dir = DIR_UP;
  5424. else if(Screen->ComboS[Combo]==1010b)
  5425. Dir = DIR_DOWN;
  5426. else if(Screen->ComboS[Combo]==0011b)
  5427. Dir = DIR_LEFT;
  5428. else if(Screen->ComboS[Combo]==1100b)
  5429. Dir = DIR_RIGHT;
  5430. else
  5431. return false;
  5432. if(Dir==Link->Dir)
  5433. return true;
  5434. return false;
  5435. }
  5436. void run(){
  5437. int PushCounter = 0;
  5438. while(true){
  5439. if(Link->Dir==DIR_UP&&!CanWalk(Link->X, Link->Y, DIR_UP, 1, false)&&Link->InputUp&&Screen->ComboT[ComboAt(Link->X+8, Link->Y+14)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+8, Link->Y+14))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5440. PushCounter++;
  5441. if(PushCounter>=CLIFF_PAUSE){
  5442. Game->PlaySound(SFX_JUMP);
  5443. Link->Jump = 2;
  5444. int Y = Link->Y;
  5445. for(int i=0; i<26; i++){
  5446. Y -= 0.61;
  5447. Link->Y = Y;
  5448. WaitNoAction();
  5449. }
  5450. PushCounter = 0;
  5451. }
  5452. }
  5453. else if(Link->Dir==DIR_DOWN&&!CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)&&Link->InputDown&&Screen->ComboT[ComboAt(Link->X+8, Link->Y+12)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+8, Link->Y+12))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5454. PushCounter++;
  5455. if(PushCounter>=CLIFF_PAUSE){
  5456. Game->PlaySound(SFX_JUMP);
  5457. Link->Jump = 1;
  5458. int Combo = ComboAt(Link->X+8, Link->Y+12);
  5459. int CliffHeight = 1;
  5460. for(int i=1; i<11; i++){
  5461. if(Screen->isSolid(ComboX(Combo)+8, ComboY(Combo)+8+16*i))
  5462. CliffHeight++;
  5463. else
  5464. break;
  5465. }
  5466. Link->Z = CliffHeight*16;
  5467. Link->Y += CliffHeight*16;
  5468. while(Link->Z>0){
  5469. WaitNoAction();
  5470. }
  5471. PushCounter = 0;
  5472. }
  5473. }
  5474. else if(Link->Dir==DIR_LEFT&&!CanWalk(Link->X, Link->Y, DIR_LEFT, 1, false)&&Link->InputLeft&&Screen->ComboT[ComboAt(Link->X+4, Link->Y+8)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+4, Link->Y+8))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5475. PushCounter++;
  5476. if(PushCounter>=CLIFF_PAUSE){
  5477. Game->PlaySound(SFX_JUMP);
  5478. Link->Jump = 2;
  5479. int X = Link->X;
  5480. for(int i=0; i<26; i++){
  5481. X -= 0.92;
  5482. if(i==13){
  5483. Link->Z += 16;
  5484. Link->Y += 16;
  5485. }
  5486. Link->X = X;
  5487. WaitNoAction();
  5488. }
  5489. while(Link->Z>0){
  5490. WaitNoAction();
  5491. }
  5492. PushCounter = 0;
  5493. }
  5494. }
  5495. else if(Link->Dir==DIR_RIGHT&&!CanWalk(Link->X, Link->Y, DIR_RIGHT, 1, false)&&Link->InputRight&&Screen->ComboT[ComboAt(Link->X+12, Link->Y+8)]==CT_CLIFF&&CheckCliffDirection(ComboAt(Link->X+12, Link->Y+8))&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5496. PushCounter++;
  5497. if(PushCounter>=CLIFF_PAUSE){
  5498. Game->PlaySound(SFX_JUMP);
  5499. Link->Jump = 2;
  5500. int X = Link->X;
  5501. for(int i=0; i<26; i++){
  5502. X += 0.92;
  5503. if(i==13){
  5504. Link->Z += 16;
  5505. Link->Y += 16;
  5506. }
  5507. Link->X = X;
  5508. WaitNoAction();
  5509. }
  5510. while(Link->Z>0){
  5511. WaitNoAction();
  5512. }
  5513. PushCounter = 0;
  5514. }
  5515. }
  5516. else{
  5517. PushCounter = 0;
  5518. }
  5519. Waitframe();
  5520. }
  5521. }
  5522. }
  5523.  
  5524. ffc script GBDungeonCliff{
  5525. void run(int CliffCombo){
  5526. int PushCounter = 0;
  5527. while(true){
  5528. if(Link->Dir==DIR_UP&&!CanWalk(Link->X, Link->Y, DIR_UP, 1, false)&&Link->InputUp&&Screen->ComboD[ComboAt(Link->X+8, Link->Y+7)]==CliffCombo&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5529. PushCounter++;
  5530. if(PushCounter>=CLIFF_PAUSE){
  5531. Game->PlaySound(SFX_JUMP);
  5532. Link->Jump = 2;
  5533. int Y = Link->Y;
  5534. for(int i=0; i<26; i++){
  5535. Y -= 0.92;
  5536. Link->Y = Y;
  5537. WaitNoAction();
  5538. }
  5539. PushCounter = 0;
  5540. }
  5541. }
  5542. else if(Link->Dir==DIR_DOWN&&!CanWalk(Link->X, Link->Y, DIR_DOWN, 1, false)&&Link->InputDown&&Screen->ComboD[ComboAt(Link->X+8, Link->Y+16)]==CliffCombo+1&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5543. PushCounter++;
  5544. if(PushCounter>=CLIFF_PAUSE){
  5545. Game->PlaySound(SFX_JUMP);
  5546. Link->Jump = 1;
  5547. int Combo = ComboAt(Link->X+8, Link->Y+12);
  5548. int CliffHeight = 1;
  5549. for(int i=1; i<11; i++){
  5550. if(Screen->isSolid(ComboX(Combo)+8, ComboY(Combo)+8+16*i))
  5551. CliffHeight++;
  5552. else
  5553. break;
  5554. }
  5555. Link->Z = CliffHeight*16-8;
  5556. Link->Y += CliffHeight*16-8;
  5557. while(Link->Z>0){
  5558. WaitNoAction();
  5559. }
  5560. PushCounter = 0;
  5561. }
  5562. }
  5563. else if(Link->Dir==DIR_LEFT&&!CanWalk(Link->X, Link->Y, DIR_LEFT, 1, false)&&Link->InputLeft&&Screen->ComboD[ComboAt(Link->X-1, Link->Y+8)]==CliffCombo+2&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5564. PushCounter++;
  5565. if(PushCounter>=CLIFF_PAUSE){
  5566. Game->PlaySound(SFX_JUMP);
  5567. Link->Jump = 2;
  5568. int X = Link->X;
  5569. for(int i=0; i<26; i++){
  5570. X -= 1.23;
  5571. Link->X = X;
  5572. WaitNoAction();
  5573. }
  5574. PushCounter = 0;
  5575. }
  5576. }
  5577. else if(Link->Dir==DIR_RIGHT&&!CanWalk(Link->X, Link->Y, DIR_RIGHT, 1, false)&&Link->InputRight&&Link->InputRight&&Screen->ComboD[ComboAt(Link->X+16, Link->Y+8)]==CliffCombo+3&&(Link->Action==LA_WALKING||Link->Action==LA_NONE)){
  5578. PushCounter++;
  5579. if(PushCounter>=CLIFF_PAUSE){
  5580. Game->PlaySound(SFX_JUMP);
  5581. Link->Jump = 2;
  5582. int X = Link->X;
  5583. for(int i=0; i<26; i++){
  5584. X += 1.23;
  5585. Link->X = X;
  5586. WaitNoAction();
  5587. }
  5588. }
  5589. }
  5590. else{
  5591. PushCounter = 0;
  5592. }
  5593. Waitframe();
  5594. }
  5595. }
  5596. }
  5597.  
  5598. item script Frogforce{
  5599. void run(){
  5600. Game->End();
  5601. }
  5602. }
  5603.  
  5604.  
  5605.  
  5606. npc script stealitems
  5607. {
  5608. void run(int min, int max, int counterA, int counterB, int counterC, int counterD, int sfx)
  5609. {
  5610. min = ( min > -1 ) ? min : 0;
  5611. max = ( max > 0 ) ? max : 1;
  5612. int num = Rand(min,max);
  5613. int counters[4] = { counterA, counterB, counterC, counterD };
  5614. int sel = counters[Rand(4)];
  5615. while(1)
  5616. {
  5617. if ( sel ) //don't affect counter 0 (life)
  5618. {
  5619. if ( Collision(this) && (Hero->HitDir > -1) )
  5620. {
  5621. Audio->PlaySound(sfx);
  5622. //Don't roll over.
  5623. if ( (Game->Counter[sel] - num) >= 0 ) Game->Counter[sel] -= num;
  5624. else
  5625. {
  5626. Game->Counter[sel] = ( num > 0 ) ? 0 : Game->Counter[sel];
  5627. }
  5628. while(Hero->HitDir > -1) { Waitframe(); } //Don't steal again unless Link is hit again.
  5629. }
  5630. }
  5631. num = Rand(min,max);
  5632. sel = counters[Rand(4)];
  5633. Waitframe();
  5634. }
  5635. }
  5636. }
  5637.  
  5638. //! The initial combo used for this ffc (on the screen) should be a rupee icon with a numeric cost.
  5639. //! The next combo in the list, should be blank.
  5640.  
  5641.  
  5642. //Combos
  5643. const int CMB_CHEST_GAME_CLOSED = 2640; //The 'closed' chest combo.
  5644. //! This should be combo type 'none', and solid.
  5645. const int CMB_CHEST_GAME_OPEN = 2641; //The closed chest combo.
  5646. //! This should be the combo immediately after CMB_CHEST_GAME_CLOSED', with a type of 'none'.
  5647.  
  5648.  
  5649. //Strings
  5650. const int MSG_CHEST_GAME_RULES = 367; //Screen->Message string that explains the game rules to the player.
  5651. const int MSG_CHEST_GAME_OVER = 366; //Screen->Message string for the end of a game round.
  5652.  
  5653. //Sounds
  5654. const int SFX_OPEN_CHEST = 20; //The sound that will play when Link opens a chest, and an item is awarded.
  5655. const int SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE = 27; //The sound to play when the player finds the special item in a chest.
  5656. const int SFX_CHEST_GAME_START = 35; //The sound to play when the player starts the game.
  5657.  
  5658. //Other Settings and Options
  5659. const int CHEST_GAME_SCREEN_D_REGISTER = 5; //The Screen->D[index] used to store if the main prize has been awarded.
  5660. const int CHEST_GAME_HOLDUP_TYPE = 4; // The type of item hold-up tp use. 4 = LA_HOLD1LAND(one hand); 5 = LA_HOLD2LAND(two hands)
  5661. const int CHEST_GAME_ALLOW_REPLAY = 0; //Set to '1' to allow the player to play again without leaving the screen.
  5662. const int TIME_INPUT_UP_OPEN_CHEST = 50; //The number of frames of inputting up will open a closed chest.
  5663. const int OPEN_CHESTS_FROM_SIDES_OR_ABOVE = 1; //Set to '0' to only permit opening them from the bottom.
  5664.  
  5665.  
  5666.  
  5667. // Chest Game FFC
  5668.  
  5669. //~ //D0: Number of chests to allow the player to open, per play.
  5670. //~ //D1: ID of special prize to award.
  5671. //~ //D2: Percentage chance of awarding special prize.
  5672. //~ //D3: Backup prize, if special prize already awarded (e.g. 100 rupees, instead of a heart piece). Set to '0' to not offer a backup prize.
  5673. //~ //D4: Cost per play.
  5674. //~ //D5: String for game rules.
  5675. //~ //D6: String to play at end of game.
  5676. //~ //D7: Set to '1' to allow replaying without leaving the screen.
  5677.  
  5678.  
  5679. ffc script ChestMiniGame{
  5680. void run(int max_chests_Link_can_open, int specialPrize, int percentMainPrize, int backupPrize, int costPerPlay, int msgRules, int msgEnd, int allowReplay){
  5681.  
  5682.  
  5683. //Populate with the IDs of prizes to award. Each index is a 1% chance.
  5684. int chestPrizes[]= { 183, 0, 30, 0, 39, 0, 39, 0, 2, 3,
  5685. 0, 0, 23, 72, 0, 72, 72, 79, 80, 3,
  5686. 0, 2, 39, 38, 71, 60, 0, 40, 0, 87,
  5687. 87, 0, 86, 80, 0, 0, 2, 29, 60, 2,
  5688. 0, 71, 73, 0, 87, 73, 0, 79, 38, 0,
  5689. 145, 80, 59, 86, 0, 0, 38, 0, 0, 0,
  5690. 0, 38, 2, 0, 60, 71, 2, 1, 73, 145,
  5691. 1, 70, 0, 78, 0, 0, 0, 80, 0, 86,
  5692. 79, 0, 70, 0, 70, 0, 0, 0, 23, 0,
  5693. 0, 2, 0, 10, 0, 38, 2, 70, 70, 86 };
  5694.  
  5695. int initialData = this->Data; //Store the initial combo, to revert, if replay is enabled.
  5696. int chestComboSpots[176];
  5697. int check;
  5698. int cmb;
  5699. int mainprize;
  5700. int timer = TIME_INPUT_UP_OPEN_CHEST;
  5701. bool openchest;
  5702. int has_opened_number_of_chests;
  5703. bool award_main_prize;
  5704. bool gameRunning;
  5705. bool gameOver;
  5706. item i;
  5707. bool giveprize;
  5708. bool awardnormalprize;
  5709.  
  5710. if ( msgRules ) Screen->Message(msgRules);
  5711. else Screen->Message(MSG_CHEST_GAME_RULES); //Show the string for the chest game rules.
  5712.  
  5713. while(true) {
  5714. if ( max_chests_Link_can_open == has_opened_number_of_chests ) gameOver = true;
  5715. if ( gameOver && ( !CHEST_GAME_ALLOW_REPLAY && !allowReplay ) || allowReplay < 0 ) break;
  5716.  
  5717. if ( gameOver && ( CHEST_GAME_ALLOW_REPLAY || allowReplay > 0 ) ) {
  5718. gameOver = false;
  5719. gameRunning = false;
  5720. this->Data = initialData;
  5721. for ( int q = 0; q < 176; q++ ) {
  5722. if ( Screen->ComboD[q] == CMB_CHEST_GAME_OPEN ) Screen->ComboD[q] = CMB_CHEST_GAME_CLOSED;
  5723. }
  5724. has_opened_number_of_chests = 0;
  5725. }
  5726.  
  5727. if ( LinkCollision(this) && Game->Counter[CR_RUPEES] > costPerPlay && ____Xor(Link->PressA,Link->PressB) && !gameRunning ) {
  5728. //If Link collides with the ffc, which should show the cost, and presses a button, start the game.
  5729. if ( SFX_CHEST_GAME_START ) Game->PlaySound(SFX_CHEST_GAME_START);
  5730. gameRunning = true;
  5731. Game->DCounter[CR_RUPEES] -= costPerPlay;
  5732. this->Data++; //increase to the next combo, removing the cost icon.
  5733. }
  5734.  
  5735.  
  5736.  
  5737. if ( gameRunning ) {
  5738.  
  5739. //Check to see if the combo above Link is a chest.
  5740.  
  5741.  
  5742. if ( Link->Dir == DIR_UP ){
  5743. cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ];
  5744.  
  5745. if ( cmb == CMB_CHEST_GAME_CLOSED ) {
  5746. if ( timer && Link->InputUp ) timer--;
  5747. if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB)) {
  5748. has_opened_number_of_chests++;
  5749. if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
  5750. Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
  5751.  
  5752. timer = TIME_INPUT_UP_OPEN_CHEST;
  5753. giveprize = true;
  5754. Link->InputUp = false;
  5755. }
  5756. }
  5757. else timer = TIME_INPUT_UP_OPEN_CHEST;
  5758. }
  5759. else if ( Link->Dir == DIR_DOWN && OPEN_CHESTS_FROM_SIDES_OR_ABOVE ){
  5760. cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ];
  5761.  
  5762. if ( cmb == CMB_CHEST_GAME_CLOSED ) {
  5763. if ( timer > 0 && Link->InputDown ) timer--;
  5764. if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB) ) {
  5765. has_opened_number_of_chests++;
  5766. if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
  5767. Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
  5768. timer = TIME_INPUT_UP_OPEN_CHEST;
  5769. giveprize = true;
  5770. Link->InputUp = false;
  5771. }
  5772. }
  5773. else timer = TIME_INPUT_UP_OPEN_CHEST;
  5774. }
  5775. else if ( Link->Dir == DIR_LEFT && OPEN_CHESTS_FROM_SIDES_OR_ABOVE ) {
  5776. cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ];
  5777. if ( cmb == CMB_CHEST_GAME_CLOSED ) {
  5778. if ( timer > 0 && Link->InputLeft ) timer--;
  5779. if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB) ) {
  5780. has_opened_number_of_chests++;
  5781. if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
  5782. Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
  5783. timer = TIME_INPUT_UP_OPEN_CHEST;
  5784. giveprize = true;
  5785. Link->InputUp = false;
  5786. }
  5787. }
  5788. else timer = TIME_INPUT_UP_OPEN_CHEST;
  5789. }
  5790. else if ( Link->Dir == DIR_RIGHT && OPEN_CHESTS_FROM_SIDES_OR_ABOVE ) {
  5791. cmb = Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir)];
  5792. if ( cmb == CMB_CHEST_GAME_CLOSED ) {
  5793. if ( timer > 0 && Link->InputRight ) timer--;
  5794. if ( timer <= 0 || ____Xor(Link->PressA,Link->PressB) ) {
  5795. has_opened_number_of_chests++;
  5796. if ( SFX_OPEN_CHEST ) Game->PlaySound(SFX_OPEN_CHEST);
  5797. Screen->ComboD[ ___AdjacentCombo(ComboAt(Link->X+8, Link->Y+8),Link->Dir) ]++;
  5798. timer = TIME_INPUT_UP_OPEN_CHEST;
  5799. giveprize = true;
  5800. Link->InputUp = false;
  5801. }
  5802. }
  5803. else timer = TIME_INPUT_UP_OPEN_CHEST;
  5804.  
  5805. }
  5806.  
  5807.  
  5808.  
  5809. if ( giveprize ) {
  5810.  
  5811. check = Rand(1,100); //Make a check, to use for determining if the main prize should e awarded.
  5812.  
  5813. if ( check <= percentMainPrize ) award_main_prize = true; //If that check passes, then we will award the main prize.
  5814.  
  5815. if ( check > percentMainPrize ) { awardnormalprize = true; check = Rand(0,SizeOfArray(chestPrizes)); }//Otherwise, reuse that var, and make a new check to determine
  5816. //the prize to award from the table.
  5817. int itm;
  5818.  
  5819. if ( !awardnormalprize && award_main_prize && !Screen->D[CHEST_GAME_SCREEN_D_REGISTER] ) { //The main prize has not been awarded, and has been randomly chosen.
  5820. Game->PlaySound(SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE); //Play the fanfare...
  5821. i = Screen->CreateItem(specialPrize); //Assign the pointer, and make the item.
  5822. itm = specialPrize; //Set the value of the item ID to a var so that we can use it for holding it up.
  5823. }
  5824. if ( !awardnormalprize && award_main_prize && Screen->D[CHEST_GAME_SCREEN_D_REGISTER] && backupPrize ) { //The main prize has already been awarded, so recheck.
  5825. Game->PlaySound(SFX_CHEST_GAME_SPECIAL_PRIZE_FANFARE); //Play the special award fanfare...
  5826. i = Screen->CreateItem(backupPrize); //Assign the pointer, and make the item.
  5827. itm = backupPrize; //Set the value of the item ID to a var so that we can use it for holding it up.
  5828. }
  5829. if ( awardnormalprize && check ) { //Otherwise, if the check to award a special prize did not pass..
  5830. Game->PlaySound(SFX_OPEN_CHEST); //otherwise, play the default.
  5831. i = Screen->CreateItem(chestPrizes[check]); //Award a normal prize, from the list.
  5832. itm = chestPrizes[check]; //Set the value of the item ID to a var so that we can use it for holding it up.
  5833.  
  5834. }
  5835. if ( check ) { //if we're awarding a prize...
  5836. i -> X = Link->X;
  5837. i -> Y = Link->Y;
  5838. if ( CHEST_GAME_HOLDUP_TYPE ) { //If the setting to hold the item overhead is enabled...
  5839. Link->Action = CHEST_GAME_HOLDUP_TYPE; //Hold the item overhead, using the value of that setting.
  5840. Link->HeldItem = itm;
  5841. }
  5842.  
  5843. if ( award_main_prize ) { Screen->D[CHEST_GAME_SCREEN_D_REGISTER] = 1; award_main_prize = false; } //Set the register so that Link cannot collect the special prize again.
  5844.  
  5845. giveprize = false;
  5846. while( Link->Action == LA_HOLD1LAND ) Waitframe();
  5847. }
  5848. else Remove(i); //if check is zero, remove the item pointer.
  5849. //This allows chances of getting nothing at all.
  5850. }
  5851.  
  5852. if ( has_opened_number_of_chests >= max_chests_Link_can_open ) {
  5853. gameOver = true;
  5854. gameRunning = false;
  5855. if ( msgEnd ) Screen->Message(msgEnd);
  5856. else Screen->Message(MSG_CHEST_GAME_OVER);
  5857.  
  5858. }
  5859.  
  5860. }
  5861.  
  5862. Waitframe();
  5863. }
  5864. //If we reach here, then the chest game is over.
  5865. this->Data = 0;
  5866. this->Script = 0;
  5867. Quit();
  5868. }
  5869.  
  5870. //Constants for AdjacentCombo()
  5871. //This now uses DIR_* constants, so you can do AdjacentCombo(cmb,Link->Dir)
  5872. //Returns the Nth combo index of a combo based on a central point, and a direction.
  5873. //For example, combo 22 + COMBO_UPRIGHT returns '7',
  5874. //as combo 7 is to the upper-right of combo 22.
  5875. int ___AdjacentCombo(int cmb, int dir){
  5876. int combooffsets[13]={-0x10, 0x10, -1, 1, -0x11, -0x0F, 0x0F, 0x11};
  5877. if ( cmb % 16 == 0 ) combooffsets[9] = 1;
  5878. if ( (cmb & 15) == 1 ) combooffsets[10] = 1;
  5879. if ( cmb < 0x10 ) combooffsets[11] = 1; //if it's the top row
  5880. if ( cmb > 0x9F ) combooffsets[12] = 1; //if it's on the bottom row
  5881. if ( combooffsets[9] && ( dir == 7 || dir == 0 || dir == 6 || dir == 0 ) ) return 0; //if the left columb
  5882. if ( combooffsets[10] && ( dir == 3 || dir == 2 || dir == 4 ) ) return 0; //if the right column
  5883. if ( combooffsets[11] && ( dir == 1 || dir == 2 || dir == 0 || dir == 0 ) ) return 0; //if the top row
  5884. if ( combooffsets[12] && ( dir == 5 || dir == 4 || dir == 6 ) ) return 0; //if the bottom row
  5885. else if ( cmb >= 0 && cmb <= 176 ) return cmb + combooffsets[dir];
  5886. else return -1;
  5887. }
  5888. //Xor comparison of two boolean values.
  5889. bool ____Xor(bool valA, bool valB){
  5890. if ( !valA && valB ) return true;
  5891. else if ( valA && !valB ) return true;
  5892. return false;
  5893. }
  5894.  
  5895.  
  5896. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement