don't click here

The internet lies: cheat code edition

Discussion in 'General Sega Discussion' started by Black Squirrel, Jul 9, 2022.

  1. Bobblen

    Bobblen

    Member
    377
    192
    43
    I added the valid Croc passwords to the wiki (based on blind faith for now, I will get round to checking at some point soon) with a credit from this forum post. Happy to change it once its on twitter or the blog of course. Curiously 2-1 and 5-5 match the psx codes but 3-1 and 4-1 do not.
    Croc: Legend of the Gobbos/Hidden content - Sega Retro

    EDIT - all four passwords work on the US version (I only check they load the level they're supposed to, not for any other effects)
     
    Last edited: Jan 15, 2024
  2. Black Squirrel

    Black Squirrel

    no reverse gear Wiki Sysop
    8,606
    2,483
    93
    Northumberland, UK
    steamboat wiki
    Thought I'd have a look into this - the ST quote comes from Fergus McGovern, top dawg of Probe who is infamous for having his head stuck in a dozen titles.

    I honestly don't know if he's correct, however I am pretty sure the two ports of Bubble Bobble and Rainbow Islands are entirely separate products which Probe were forced to jam together. Bubble Bobble was ported by Probe, but Rainbow Islands was ported by Graftgold - both games show a credits screen if you wait long enough on their titles.


    Graftgold were responsible for porting Rainbow Islands to the Amiga and Atari ST in 1988/89 - there are even some shared staff, however I don't think this is ST code running on a Saturn. I think it was written in C... because if you have a look at the CD-ROM, "2.BIN" contains hoards of uncompiled C code:
    Code (Text):
    1. void Refresh(void)
    2. {
    3.   ScreenModeInfo *Scr = SCREEN(USBuffer);
    4.  
    5.   if (NewLook==0)
    6.   {
    7.     memcpy(Scr->Address,(WorkMem->Address)+(MasterY *320),320*224);
    8.   }
    9.   else
    10.   {
    11.     if (CurrentPlayer->PlayerIsland == 4 || CurrentPlayer->PlayerIsland == 6)
    12.       Refresh2();
    13.     else
    14.       Refresh3();               //      Refresh1();
    15.   }
    16.  
    17. }
    18.  
    19. UBYTE NRemap[]=      /* player2 remap table for newlook graphics only */
    20. {
    21.    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
    22.    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
    23.    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
    24.    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
    25.    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
    26.    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
    27.    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
    28.    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
    29.    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
    30.    0x5f,0x5e,0x5d,0x5c,0x5b,0x5a,0x59,0x58,0x57,0x56,0x55,0x54,0x53,0x52,0x51,0x50,
    31.    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
    32.    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
    33. };
    34.  
    35. /* ----------------------------------------------------------------------------
    36. SimplePlotPlayer
    37.  
    38.     Standard plotter adapted to remap player
    39.  
    40. --------------------------------------------------------------------------- */
    41. void SimplePlotPlayer(int xat,int yat,Memory *Data,int Frame)
    42. {
    43.   ScreenModeInfo *Scr = SCREEN(USBuffer);
    44.   struct SpriteBPPS *Base;
    45.   struct InfoBPPS *SPInfo;
    46.  
    47.   /* the next line is a three fold data integrity check : */
    48.   if (*((int*) Data->Address) != 0x53505042) return;
    49.   Base = (SpriteBPPS *) Data->Address;
    50.   SPInfo = Base->InfoBPPS + ((Frame >= Base->Sprites) ? 0 : Frame);
    51.   {
    52.     char *SpDat = Data->Address + SPInfo->SpriteAt; /* read from here */
    53.     char *Addr = Scr->Address;
    54.     int LineSize = Scr->LineSize;
    55.     int XLimit = Scr->XSize;
    56.     int YLimit = Scr->YSize;
    57.     int XPos = xat + Scr->XOrigin - SPInfo->XOfst;
    58.     int YPos = yat + Scr->YOrigin - SPInfo->YOfst;
    59.     int Lines = SPInfo->YSize; /* XSize is not that important */
    60.     Addr += YPos * LineSize; /* assume byte per pixel screen */
    61.     while((Lines--) && (YPos < YLimit))
    62.     {
    63.       int xp = XPos;
    64.       int Strips = *SpDat++;
    65.       while(Strips--)
    66.       {
    67.         int Skip = *SpDat++;
    68.         int Plot = *SpDat++;
    69.         char *DtOfs = SpDat;
    70.         SpDat += Plot;
    71.         xp += Skip;
    72.         /* clipping : */
    73.         if (YPos >= 0)
    74.         {
    75.           if (((xp + Plot) > 0) && (xp < XLimit))
    76.           {
    77.             int Draw = Plot;
    78.             int Over,atx = xp;
    79.             if (atx < 0)
    80.             {
    81.               Draw += atx;
    82.               DtOfs -= atx;
    83.               atx = 0;
    84.             }
    85.             Over = (atx + Draw) - XLimit;
    86.             if (Over > 0)
    87.             {
    88.               Draw -= Over;
    89.             }
    90.             while(Draw-- > 0)
    91.             {
    92.               Addr[atx++] = NRemap[(*DtOfs++)];
    93.             }
    94.           }
    95.         }
    96.         xp += Plot;
    97.       }
    98.       YPos++;
    99.       Addr += LineSize;
    100.     }
    101.   }
    102. }
    103.  
    104. /* ----------------------------------------------------------------------------
    105. ReverseXPlotPlayer
    106.  
    107.       reverse x plotter
    108.  
    109. --------------------------------------------------------------------------- */
    110. void ReverseXPlotPlayer(int xat,int yat,Memory *Data,int Frame)
    111. {
    112.   ScreenModeInfo *Scr = SCREEN(USBuffer);
    113.   struct SpriteBPPS *Base;
    114.   struct InfoBPPS *SPInfo;
    115.   char *SpDat;
    116.   char *Addr = Scr->Address;
    117.   int LineSize = Scr->LineSize;
    118.   int XLimit = Scr->XSize;
    119.   int YLimit = Scr->YSize;
    120.   int XPos;
    121.   int YPos;
    122.   int Lines;
    123.   int xp;
    124.   int Strips;
    125.   int Skip;
    126.   int Plot;
    127.   char *DtOfs;
    128.   int Off;
    129.  
    130.   /* the next line is a three fold data integrity check : */
    131.   if (*((int*) Data->Address) != 0x53505042)
    132.     return;
    133.   Base = (SpriteBPPS *) Data->Address;
    134.   SPInfo = Base->InfoBPPS + ((Frame >= Base->Sprites) ? 0 : Frame);
    135.   SpDat = Data->Address + SPInfo->SpriteAt; /* read from here */
    136.   XPos = xat + Scr->XOrigin - SPInfo->XOfst + SPInfo->XSize -1;
    137.   YPos = yat + Scr->YOrigin - SPInfo->YOfst;
    138.   Lines = SPInfo->YSize; /* XSize is not that important */
    139.  
    140.   Addr += YPos * LineSize; /* assume byte per pixel screen */
    141.  
    142.   while((Lines--) && (YPos < YLimit))
    143.   {
    144.     xp = XPos;
    145.     Strips = *SpDat++;
    146.    
    147.     while(Strips--)
    148.     {
    149.       Skip = *SpDat++;
    150.       Plot = *SpDat++;
    151.       DtOfs = SpDat;        /* pointer into strip */
    152.  
    153.       SpDat += Plot;
    154.       xp -= Skip;
    155.      
    156.       /* clipping : */
    157.       if (YPos >= 0)        /* don't plot if off the top of screen */
    158.       {
    159.         /* right clipping */
    160.  
    161.         if (xp >= XLimit)   /* off the rhs */
    162.         {
    163.           Off = xp-XLimit+1;/* by 'Off' Pixels */
    164.  
    165.           if (Off >= Plot)  /* don't plot strip at all! */
    166.           {
    167.             xp -= Plot;
    168.             continue;       /* go to Next Strip */
    169.           }
    170.                             /* can plot some of strip */
    171.           Plot -= Off;
    172.           xp -= Off;
    173.           DtOfs += Off;
    174.  
    175.         }
    176.        
    177.         /* left clipping */
    178.         if (xp>=0)          /* only do if on screen */
    179.         {
    180.           if (Plot>xp+1)    /* can't plot full strip */
    181.             Plot = xp+1;    /* so truncate */
    182.  
    183.  
    184.           while(Plot--)
    185.           {
    186.             Addr[xp--] = NRemap[(*DtOfs++)];
    187.           }
    188.         }
    189.  
    190.       }
    191.     }
    192.     YPos++;
    193.     Addr += LineSize;
    194.   }
    195. }
    196.  
    197.       if (!Err)
    198.             Err=DoFileLoad(MainMem,"ending2.ggi",&LoadedSprites,
    199.                         NULL,MEM_WORD_32_ALIGNED,"gfx:loaded",FL_GRAPHICS);
    200.       if (!Err)
    201.         {
    202.             InitGGI(LoadedSprites); /* process ggi for endian ... */
    203.        BuildSprites(LoadedSprites,FramesInMAIN);
    204.         }
    205.  
    206.       LoadedIsland = (-1);
    207.       break;
    208.     }
    209.  
    210.      case GF_MAPS:
    211.      {
    212.         break;      /* Maps already in PC data */
    213.        GetSpriteBlocks();   /* Allocate sprite blocks and form linked list */
    214.         SetPlayers();
    215.         SetPlayerDevices(); /* Select default control methods in Players */
    216.         PrintFront(TopLegend);
    217.          
    218.         if (MaxCredits == 0)
    219.           GState = GS_START_DEMO;
    220.          else
    221.         GState = GS_TITLE_2;
    222.       break;
    223.     }
    224.  
    225.      case GS_EXITMENU:
    226.      {
    227.       SpriteClear();
    228.         DState = 0;
    229.       ClearGameScreen(SC_BLACK);
    230.         if (AnalogInput.DigitalGatedButtons & AKeyMenuUp)
    231.         {
    232.             if (ExitOption > 0)
    233.             {
    234.                 ExitOption--;
    235.                 SoundRequest(SFXMenuUD,4);
    236.             }
    237.         }
    238.         else if (AnalogInput.DigitalGatedButtons & AKeyMenuDown)
    239.         {
    240.             if (ExitOption < (MAX_EXIT_OPTIONS - 1))
    241.             {
    242.                 ExitOption++;
    243.                 SoundRequest(SFXMenuUD,4);
    244.             }
    245.         }
    246.         else if (AnalogInput.DigitalGatedButtons & (AKeyMenuSelect))
    247.         {
    248.             if (ExitOption == EXIT_YES)
    249.             {
    250.                 Err = &UserExit;
    251.             }
    252.             else
    253.             {
    254.                 ExitOption = EXIT_NO;
    255.                 GState = GS_TITLE_2;
    256.                 SoundRequest(SFXMenuButton,3);
    257.             }
    258.         }
    259.  
    260.         *ExitCursorPos = ExitOption*16 + 0x58;
    261.         ClearGameScreen(SC_UNPAUSE);
    262.         PrintFront(ExitMenu);
    263.         PrintFront(ExitCursor);
    264.         break;
    265.      }
    266.  
    267.  
    268.     case GS_TITLE_2:
    269.     {
    270.       /* this is where end of game loops back to !!! */
    271.       PrintFront(PrintCredit);
    272.  
    273.       SpriteClear();
    274.       SystemFlags &= ~Quit;
    275.       SystemFlags &= ~Paused;                    /* UN - PAUSE */
    276.       GameFlags &= ~SuspendSprites;
    277. //      SoundReset();
    278.       HintFlag=0;
    279.       Playback=0;
    280.         if (CurrentPlayer->PlayerNumber != 1)
    281.         {
    282.             PLAYER *a0 = CurrentPlayer;
    283.             CurrentPlayer = BenchPlayer;
    284.             BenchPlayer = a0;
    285.         }
    286.  
    287.       GState = GS_TITLE_3;
    288.       break;
    289.     }
    290.     case GS_TITLE_3:
    291.     {
    292.       ActiveOption=0;
    293.       Players=0;
    294.       Cheats=0;
    295.       CheatNumber=(-1);
    296.       KevCheatFrame=0;
    297.       KevCheatFrame2=0;
    298.       *(CheatTen) = Term;
    299.       PlayerStencil.PlayerMaximum = 0x00999999;
    300.  
    301.       Money();
    302.  
    303.       if (Credit)
    304.         GState = GS_MONEY_IN;
    305.       else
    306.         GState = GS_TITLE_LOOP;
    307.  
    308.       break;
    309.     }
    310.     case GS_TITLE_LOOP:
    311.     {
    312.         int i;
    313.         KeyIndex = 0;           /* Reset cheat input */
    314.         for (i=0; i<8; i++)
    315.         {
    316.             PrintCheat[4+i]='.';
    317.         }
    318.  
    319.       SpriteClear();
    320.       ClearGameScreen(SC_BLACK);
    321.       InitiateSprite(R_InitLogo);
    322.       InitiateSprite(R_InitTaito0);
    323.       InitiateSprite(R_InitHeartList);
    324.  
    325.       PrintFront(TitleScreen);
    326.       PrintFront(PrintCredit);
    327.       if (Money())
    328.         GState = GS_MONEY_IN;
    329.       else
    330.         GState = GS_TITLE_LOOP_1;
    331.      
    332.       break;
    333.     }
    334.     case GS_TITLE_LOOP_1:
    335.     {
    336.  
    337.       ChangePalette(P_TITLES,16);
    338.  
    339.       Timer=3*Second;
    340.       if (Money())
    341.         GState = GS_MONEY_IN;
    342.       else
    343.         GState = GS_TITLE_LOOP_2;
    344.       break;
    345.     }
    346.     case GS_TITLE_LOOP_2:     /* loop on Timer static logo */
    347.     {
    348.       if (Money())
    349.         GState = GS_MONEY_IN;
    350.       else if (Timer>0)
    351.       {
    352.           CheatCodes();
    353.       }
    354.       else
    355.       {
    356.         Timer = 7*Second;
    357.         GState = GS_TITLE_LOOP_3;
    358.  
    359. #if TEST_DEMO
    360.   GState = GS_START_DEMO;
    361. #endif
    362.       }
    363.        
    364.       break;
    365.     }
    366.     case GS_TITLE_LOOP_3:     /* loop on Timer while cycling logo */
    367.     {
    368.       if (Money())
    369.         GState = GS_MONEY_IN;
    370.       else if (Timer>0)
    371.       {
    372.         CycleLogo();          
    373.           CheatCodes();
    374.       }
    375.       else
    376.       {
    377.        
    378.         ChangePalette(P_BLACK,16);
    379.         GState = GS_TITLE_LOOP_FADE;
    380.       }
    381.        
    382.       break;
    383.     }
    384.  
    385.     case GS_TITLE_LOOP_FADE:
    386.     {
    387.  
    388.       if (Money())
    389.         GState /* AMP.C -------------------------------------------------------------------*/
    390. #include <stdlib.h>
    391. #include <string.h>
    392.  
    393. #include  "GLibrary.h"      /* Graftgold library header */
    394.  
    395. #include "amp.h"      
    396. #include "game.h"
    397. #include "fruit.h"
    398. #include "resident.xxh"
    399. #include "text.h"
    400. #include "sound.h"
    401. #include "pal.h"
    402. #include "plot.h"
    403. #include "support.h"    /* for definition of 'Second' */
    404.  
    405. extern UWORD _RandomNumber();
    406. extern SWORD _SinCos();
    407. extern SWORD  Sine14;
    408. extern SWORD  Cosine14;
    409. extern UWORD PlotTimer;
    410.  
    411. /* NEW 22/3/96 KH */
    412. /* purge objects further than this from visible screen (in pixels) */
    413. #define PURGE_RANGE  (7*8)      /* In pixels */
    414.  
    415. #define Limit(p1,p2,p3) {if (p1<(p2)) p1=(p2);else if (p1>(p3)) p1=(p3);}
    416.  
    417.  
    418.  
    419. /* --------------------------------------------------------------------------
    420. RandNum
    421. -------------------------------------------------------------------------- */
    422. UDWORD RandNum(void)
    423. {
    424.   return(Rndm()); /* use GLIB machine independent random number routine */
    425. }
    426.  
    427.  
    428. void FrameUpdate(void);
    429. UWORD AutoAnimate(SPRITE *Current);
    430. PLAYER *AddStatistic(UWORD d0);
    431. SPRITE *ActivateAMP(AMPDATA *a0);
    432. SPRITE *ActivateAMPRES(UWORD Res);
    433. static void JumpOption(void);
    434. static void StepOption(void);
    435. static void SearchOption(void);
    436. UWORD OriginUnder(SWORD d0, SWORD d1, UWORD **Pa0, UWORD **Pa1);
    437. void IdentifyCellLeft(SWORD d0);
    438. void IdentifyCellRight(SWORD d0);
    439. UWORD CellCheck(SWORD d4,SWORD d5,SWORD d6,UWORD **pa0,UWORD **pca0);
    440.  
    441. static void UnplotCollision(void);
    442. static void PlotCollision(void);
    443. static void PreparePlayer(PLAYER *a0,UWORD d0,UWORD d1);
    444. static void Stop(void);
    445. static void WalkCheckX(void);
    446. static void WalkCheckY(void);
    447. static void JumpUpCheckX(void);
    448. static void JumpDownCheckX(void);
    449. static void FallCheckX(void);
    450. static void FallCheckY(void);
    451. static void RideCheckX(void);
    452. static void RideCheckY(void);
    453. static void CrashCheck(void);
    454.  
    455. void ActivateSpecial(void);
    456. static void IdentifyCell( SWORD d0);
    457. static void AddDiamond(SWORD d0,UWORD d6,UWORD d7);
    458.  
    459.  
    460. void MDelay(void);
    461. void MLoop(void);
    462. void MEndLoop(void);
    463. void MPolarSpeed(void);
    464. void MPolarTurn(void);
    465. void MPolarFace(void);
    466. void MPolarAccelerate(void);
    467. void MMoveUpdate(void);
    468. void MRandomMask(void);
    469. void MGotoDependingOn(void);
    470. void MMouseDirect(void);
    471. void MJoystickDirect(void);
    472. void MAnimate(void);
    473. void MFrame(void);
    474. void MPlot(void);
    475. void MAVector(void);
    476. void MMVector(void);
    477. void MLVector(void);
    478. void MFollow(void);
    479. void MBoundaryX(void);
    480. void MBoundaryY(void);
    481. void MDie(void);
    482. void MMasterUpdate(void);
    483. void MMapRelative(void);
    484. void MPriority(void);
    485. void MModifyField(void);
    486. void MActivate(void);
    487. void MCollision(void);
    488. void MSetFlag(void);
    489. void MClearFlag(void);
    490. void MPassThrough(void);
    491. void MCollisionWith(void);
    492. void MRelativeUpdate(void);
    493. void MCheckFlag(void);
    494. void MPushScroll(void);
    495. void MDeclareBlock(void);
    496. void MScore(void);
    497. void MTransform(void);
    498. void MSetField(void);
    499. void MSeaRise(void);
    500. void MBaseFace(void);
    501. void MDrownCheck(void);
    502. void MManualMode(void);
    503. void MPlayerMove(void);
    504. void MPlayerFace(void);
    505. void MAlternatePlot(void);
    506. void MPlayerFire(void);
    507. void MSeaFall(void);
    508. void MReleaseBlock(void);
    509. void MGoalCheck(void);
    510. void MFosterParent(void);
    511. void MCountRainbows(void);
    512. void MStarFire(void);
    513. void MForceScroll(void);
    514. void MClearParentFlag(void);
    515. void MRelativeBoundaryX(void);
    516. void MRelativeBoundaryY(void);
    517. void MQuickSetSpeed(void);
    518. void MCheckExternalFlag(void);
    519. void MGetRainbowBlock(void);
    520. void MFreeRainbowBlock(void);
    521. void MBuildCell(void);
    522. void MDeleteRainbowCells(void);
    523. void MCheckPlayerFlag(void);
    524. void MHideCells(void);
    525. void MPurgeRainbow(void);
    526. void MPlayerRestart(void);
    527. void MSetTimer(void);
    528. void MSetExternalFlag(void);
    529. void MClearExternalFlag(void);
    530. void MGetParentPosition(void);
    531. void MAllocateRainbowBlock(void);
    532. void MPrintPosition(void);
    533. void MAllocateFruitBlock(void);
    534. void MGetFruitBlock(void);
    535. void MFreeFruitBlock(void);
    536. void MDeallocateFruitBlock(void);
    537. void MDeleteFruitCells(void);
    538. void MFruitSearch(void);
    539. void MBuildSprite16(void);
    540. void MGetFruitNumber(void);
    541. void MGetScoreNumber(void);
    542. void MGravity(void);
    543. void MFruitFrame(void);
    544. void MFruitKill(void);
    545. void MSetGoalIn(void);
    546. void MFireGoalIn(void);
    547. void MFallCheck(void);
    548. void MMapLocate(void);
    549. void MGetChestBlock(void);
    550. void MFruitTrajectory(void);
    551. void MForceScoreNumber(void);
    552. void MRoundX(void);
    553. void MBigBossCheck(void);
    554. void MCheckRound(void);
    555. void MCheckScroll(void);
    556. void MAcknowledgeSpecial(void);
    557. void MPlayerFeatures(void);
    558. void MScaleSpeed(void);
    559. void MCrashOption(void);
    560. void MQuickModifySpeed(void);
    561. void MTransferSprite(void);
    562. void MSnapPositions(void);
    563. void MClearBusy(void);
    564. void MSetUsed(void);
    565. void MBranchSet(void);
    566. void MGetHiddenNumber(void);
    567. void MSetPlayerFlag(void);
    568. void MRangeField(void);
    569. void MFourFruit(void);
    570. void MPalette(void);
    571. void MBigFruitTrajectory(void);
    572. void MCancelOptions(void);
    573. void MStarControl(void);
    574. void MStarRelease(void);
    575. void MBlanketCollision(void);
    576. void MRainbowActivate(void);
    577. void MGetPrintPosition(void);
    578. void MStatistic(void);
    579. void MSpinFrames(void);
    580. void MPowerBar(void);
    581. void MProduce(void);
    582. void MStretch(void);
    583. void MFaceSpeedX(void);
    584. void MSetParentFlag(void);
    585. void MRelativeBounceX(void);
    586. void MRelativeBounceY(void);
    587. void MHitPlayer(void);
    588. void MLocatePlayerX(void);
    589. void MMeanieSpeedX(void);
    590. void MAcknowledgeBigSpecial(void);
    591. void MAdvanceToSeven(void);
    592. void MAdvanceToEight(void);
    593. void MDropTurnCheck(void);
    594. void MDropCheck(void);
    595. void MBlockCheck(void);
    596. void MGetBigScoreNumber(void);
    597. void MKillUpdate(void);
    598. void MKill(void);
    599. void MFirstIsland(void);
    600. void MPositionIsland(void);
    601. void MShowGem(void);
    602. void MQuickModifyPosition(void);
    603. void MHitBigBoss(void);
    604. void MOpenSilverDoor(void);
    605. void MMeanieSmallFace(void);
    606. void MMeanieLargeFace(void);
    607. void MMeanieSmallFrame(void);
    608. void MMeanieLargeFrame(void);
    609. void MMeanieSmallBase(void);
    610. void MMeanieLargeBase(void);
    611. void MHitBossOnce(void);
    612. void MRainbowRide(void);
    613. void MSlopeFrame(void);
    614. void MLocatePlayerY(void);
    615. void MMeanieSpeedY(void);
    616. void MLocatePlayerPolar(void);
    617. void MMeanieSpeedPolar(void);
    618. void MHurryAngry(void);
    619. void MPurgeCheck(void);
    620. extern void MRainbowTouch(void);
    621. void MPlayerAboveBy(void);
    622. void MRelativeStopX(void);
    623. void MLandSearchUp(void);
    624. void MWebAlign(void);
    625. extern void MRainbowBounce(void);
    626. void MSideBounce(void);
    627. void MGenerate(void);
    628. void MSelectPolarX(void);
    629. void MReadyToFire(void);
    630. void MRainbowReverse(void);
    631. void MPolarVeer(void);
    632. void MBeeMove(void);
    633. void MFireOption(void);
    634. void MShootRainbow(void);
    635. void MPurgeCheckOption(void);
    636. void MHitSolid(void);
    637. void MGroundCheck(void);
    638. void MSpeedXFace(void);
    639. void MStorePlayerY(void);
    640. void MLevelWithPlayerY(void);
    641. void MTopBounce(void);
    642. void MFanFire(void);
    643. void MReverseSpeedX(void);
    644. void MReverseSpeedY(void);
    645. void MCheckFruitSlots(void);
    646. void MRainbowContact(void);
    647. void MSelectiveFruitKill(void);
    648. void MSideHit(void);
    649. void MSound(void);
    650. void MMultiSFX(void);
    651. void MExtendPoints(void);
    652. void MTune(void);
    653. void MTheme(void);
    654. void MFastTheme(void);
    655. void MBigBossTheme(void);
    656. void MDisplayHearts(void);
    657. void MHurrySound(void);
    658. void MCompletedSound(void);
    659. void MShowPower(void);
    660. void MRemoveLife(void);
    661. void MCameraShake(void);
    662. void MPanHurrySound(void);
    663. void MEndCompletedSound(void);
    664.  
    665. UWORD GlobalCollision=0;   /* Global class of collision                     */
    666.                                                                                                                    
    667. SPRITE SpriteReady;
    668.  
    669.  
    670. SWORD IDRainbowY=0;
    671. SWORD IDRainbowCell=0;
    672. SWORD IDRainbowOffset=0;
    673.  
    674. /* -------------------------------------------------------------------------
    675. ;
    676. ; Master co-ordination blocks, link sprite control blocks to cell cluster
    677. ; DefineBlock must be first to initialise cell offset, followed by all
    678. ; rainbow blocks, then all fruit blocks.
    679. ;
    680. ;------------------------------------------------------------------------- */
    681. RAINBOW RainbowBlock12={0,0,0,0,              221};
    682. RAINBOW RainbowBlock11={&RainbowBlock12,0,0,0,201};
    683. RAINBOW RainbowBlock10={&RainbowBlock11,0,0,0,181};
    684. RAINBOW RainbowBlock9={&RainbowBlock10,0,0,0,161};
    685. RAINBOW RainbowBlock8={&RainbowBlock9,0,0,0,141 };
    686. RAINBOW RainbowBlock7={&RainbowBlock8,0,0,0,121 };
    687. RAINBOW RainbowBlock6={&RainbowBlock7,0,0,0,101 };
    688. RAINBOW RainbowBlock5={&RainbowBlock6,0,0,0,81  };
    689. RAINBOW RainbowBlock4={&RainbowBlock5,0,0,0,61  };
    690. RAINBOW RainbowBlock3={&RainbowBlock4,0,0,0,41  };
    691. RAINBOW RainbowBlock2={&RainbowBlock3,0,0,0,21  };
    692. RAINBOW RainbowBlock1={&RainbowBlock2,0,0,0,1   };
    693.  
    694. FRUIT FruitBlock22 = {0,0,0,0,241 +84,NULL,0};
    695. FRUIT FruitBlock21 = {&FruitBlock22,0,0,0,241 +80,NULL,0};
    696. FRUIT FruitBlock20 = {&FruitBlock21,0,0,0,241 +76,NULL,0};
    697. FRUIT FruitBlock19 = {&FruitBlock20,0,0,0,241 +72,NULL,0};
    698. FRUIT FruitBlock18 = {&FruitBlock19,0,0,0,241 +68,NULL,0};
    699. FRUIT FruitBlock17 = {&FruitBlock18,0,0,0,241 +64,NULL,0};
    700. FRUIT FruitBlock16 = {&FruitBlock17,0,0,0,241 +60,NULL,0};
    701. FRUIT FruitBlock15 = {&FruitBlock16,0,0,0,241 +56,NULL,0};
    702. FRUIT FruitBlock14 = {&FruitBlock15,0,0,0,241 +52,NULL,0};
    703. FRUIT FruitBlock13 = {&FruitBlock14,0,0,0,241 +48,NULL,0};
    704. FRUIT FruitBlock12 = {&FruitBlock13,0,0,0,241 +44,NULL,0};
    705. FRUIT FruitBlock11 = {&FruitBlock12,0,0,0,241 +40,NULL,0};
    706. FRUIT FruitBlock10 = {&FruitBlock11,0,0,0,241 +36,NULL,0};
    707. FRUIT FruitBlock9 =  {&FruitBlock10,0,0,0,241 +32,NULL,0};
    708. FRUIT FruitBlock8 =  {&FruitBlock9 ,0,0,0,241 +28,NULL,0};
    709. FRUIT FruitBlock7 =  {&FruitBlock8 ,0,0,0,241 +24,NULL,0};
    710. FRUIT FruitBlock6 =  {&FruitBlock7 ,0,0,0,241 +20,NULL,0};
    711. FRUIT FruitBlock5 =  {&FruitBlock6 ,0,0,0,241 +16,NULL,0};
    712. FRUIT FruitBlock4 =  {&FruitBlock5 ,0,0,0,241 +12,NULL,0};
    713. FRUIT FruitBlock3 =  {&FruitBlock4 ,0,0,0,241 + 8,NULL,0};
    714. FRUIT FruitBlock2 =  {&FruitBlock3 ,0,0,0,241 + 4,NULL,0};
    715. FRUIT FruitBlock1 =  {&FruitBlock2 ,0,0,0,241 + 0,NULL,0};
    716.  
    717.                                    
    718. #define DefineRainbow(p1)       \
    719.   {0,0,NULL,0xa8,0 ,0,p1},      \
    720.   {0,0,NULL,0xa8,1 ,0,p1},      \
    721.   {0,0,NULL,0x2c,2 ,0,p1},      \
    722.   {0,0,NULL,0xac,3 ,0,p1},      \
    723.   {0,0,NULL,0xac,4 ,0,p1},      \
    724.   {0,0,NULL,0xa8,5 ,0,p1},      \
    725.   {0,0,NULL,0x2a,6 ,0,p1},      \
    726.   {0,0,NULL,0xa0,7 ,0,p1},      \
    727.   {0,0,NULL,0xa0,8 ,0,p1},      \
    728.   {0,0,NULL,0xa4,9 ,0,p1},      \
    729.   {0,0,NULL,0x2e,10,0,p1},      \
    730.   {0,0,NULL,0xac,11,0,p1},      \
    731.   {0,0,NULL,0xab,12,0,p1},      \
    732.   {0,0,NULL,0xa0,13,0,p1},      \
    733.   {0,0,NULL,0xa4,14,0,p1},      \
    734.   {0,0,NULL,0xaf,15,0,p1},      \
    735.   {0,0,NULL,0xab,16,0,p1},      \
    736.   {0,0,NULL,0xa0,17,0,p1},      \
    737.   {0,0,NULL,0xa4,18,0,p1},      \
    738.   {0,0,NULL,0xaf,19,0,p1},
    739.                                    
    740. //#define DefineFruit(p1)                  \
    741. //  {0,0,0,0x80,0,0,p1},                   \
    742. //  {0,0,0,0x80,1,0,p1},                   \
    743. //  {0,0,0,0x80,2,0,p1},                   \
    744. //  {0,0,0,0x80,3,0,p1},
    745.  
    746. #define RainbowCells (&CellBlocks[1])
    747.  
    748. CELL CellBlocks[]=
    749. {
    750.   {0,0,0,0,0,0,0},  /* Dummy zero entry */
    751. /* RainbowCells */
    752.   DefineRainbow(&RainbowBlock1)
    753.   DefineRainbow(&RainbowBlock2 )
    754.   DefineRainbow(&RainbowBlock3 )
    755.   DefineRainbow(&RainbowBlock4 )
    756.   DefineRainbow(&RainbowBlock5 )
    757.   DefineRainbow(&RainbowBlock6 )
    758.   DefineRainbow(&RainbowBlock7 )
    759.   DefineRainbow(&RainbowBlock8 )
    760.   DefineRainbow(&RainbowBlock9 )
    761.   DefineRainbow(&RainbowBlock10)
    762.   DefineRainbow(&RainbowBlock11)
    763.   DefineRainbow(&RainbowBlock12)
    764.  
    765. };
    766.  
    767.  
    768.  
    769. RAINBOW ActiveRainbows={&ActiveRainbows,&ActiveRainbows};
    770. UWORD InactiveRainbowCount=12;
    771. RAINBOW InactiveRainbows={&RainbowBlock1};
    772.  
    773. UWORD InactiveFruitCount=22;
    774. FRUIT ActiveFruit={&ActiveFruit,&ActiveFruit};
    775. FRUIT InactiveFruit ={&FruitBlock1};
    776.  
    777. /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    778. /* ^^^^THIS SECTION DUMMIES LOADED RESIDENT.DAT ^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    779. /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    780. extern Memory *Resident;
    781. extern AMPDATA **ResAMPs;
    782. /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    783. /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    784.  
    785. /* this bit builds REFS for AMPs CSizes and CBlocks */
    786. #include "amptable.h"
    787. /* this bit builds DEFS for AMPs CSizes and CBlocks */
    788. #define XXHDEF
    789. #include "amptable.h"  
    790.  
    791.  
    792. /* ;---------------------------------------------------------------------------   */
    793.                                     /* ; Imports                                                                     */
    794.                                     /*       XRef   Print,Charac,PrintOne,Print_X,Print_Y                              */
    795.                                     /*       XRef   PlotMethods                                                         */
    796.                                     /*       XRef   ExternalFlags                                                      */
    797.                                     /*       XRef   SystemFlags,GameFlags,GameFlags2,GameFlags3                        */
    798.                                     /*       XRef   CharacterBuffer,ScoreMaintain,CharacterReal                        */
    799.                                     /*       XRef   MasterX,MasterY,PlayerNumber,Cheats                                 */
    800.                                     /*                                                                               */
    801.                                     /*       XRef   ColourBarReload,ReadySync,ColourReload                              */
    802.                                     /*       XRef   ScoreRefresh,SessionEnded,DoorTaken                                 */
    803.                                     /*       XRef   SuspendSprites,HurryMessage,GoalAchieved                           */
    804.                                     /*       XRef   RedStar,YellowStar,ClockTick,GraftgoldStar                        */
    805.                                     /*       XRef   GraftgoldKey,BonusInhibit                                          */
    806.                                     /*                                                                               */
    807.                                     /*       XRef   JoystickLR,JoystickUD,JoystickFire,JoystickGate                     */
    808.                                     /*       XRef   _ScrollRequest,DisplayStatic,JoystickJump                           */
    809.                                     /*       XRef   SeaLevel,ClipSea,NormalPalette                                    */
    810.                                     /*       XRef   CharacterCutoff,AMPWalkFast                                       */
    811.                                     /*       XRef   AMPStand,AMPWalk,AMPJumpUp,AMPJumpDown,AMPFall                     */
    812.                                     /*       XRef   RoundStages,BarrelTop,BuildFrontCharacter                           */
    813.                                     /*       XRef   BuildTop,MasterTop,MasterBottom,BuildCharacter                     */
    814.                                     /*       XRef   CellBlocks,ActiveRainbows,InactiveRainbows                        */
    815.                                     /*       XRef   InactiveRainbowCount                                                */
    816.                                     /*       XRef   ActiveFruit,InactiveFruit,InactiveFruitCount                        */
    817.                                     /*       XRef   FruitCell00,FruitMeanie,SecretY                                    */
    818.                                     /*       XRef   InitHidden                                                         */
    819.                                     /*       XRef   HiddenValues,ScoreValues                                          */
    820.                                     /*       XRef   InitLeftStar,InitRightStar,InitCompleted,Init1Up                  */
    821.                                     /*       XRef   InitWing1,InitWing2,InitAngelPerm,InitAngelTemp                  */
    822.                                     /*       XRef   InitHundredGrand,InitBigCompleted                                 */
    823.                                     /*       XRef   InitGem,InitGemFrame,InitGemX,InitSmallLifeX                        */
    824.                                     /*       XRef   InitClear,InitClearX,InitLargeLife,InitSmallLife                  */
    825.                                     /*       XRef   ActiveOption,ForceFruit,CountOption                                 */
    826.                                     /*       XRef   InitLightning,InitDrugs,InitCup,InitClock                           */
    827.                                     /*       XRef   InitFlashing,InitBigMoney                                          */
    828.                                     /*       XRef   InitFourFruit,InitFourDisplace,InitFourX                           */
    829.                                     /*       XRef   InitRedStar,InitRedCourse                                          */
    830.                                     /*       XRef   InitBalloonControl                                                */
    831.                                     /*       XRef   InitYellowStar,InitYellowCourse                                    */
    832.                                     /*       XRef   InitGraftgoldStar,InitGraftgoldCourse                              */
    833.                                     /*       XRef   InitWave1,InitWave2,KillCount,KillAccumulate                        */
    834.                                     /*       XRef   RoundTime,Players,BigBossPower,BigScoreValues                     */
    835.                                     /*       XRef   CompletedCount                                                      */
    836.                                     /*                                                                               */
    837.                                     /*       XRef   ScreenOne,ScreenTwo                                                */
    838.                                     /*                                                                               */
    839.                                     /*       XRef   InitMiniX,InitMiniY,InitMiniFrame                                 */
    840.                                     /*       XRef   InitNumberX,InitNumberY,InitNumberFrame                           */
    841.                                     /*       XRef   InitBigGem,InitGemDisplace,InitSilverDoor                           */
    842.                                     /*       XRef   InitFlashingGem,InitHeart                                          */
    843.                                     /*                                                                               */
    844.                                     /*       XRef   Mouse,ControlMethod1,ControlMethod2                                 */
    845.                                     /*                                                                               */
    846.                                     /* ; Exports                                                                     */
    847.                                     /*       XDef   ScreenBase,ScreenSeen,ScreenUnseen,ScreenSaved                     */
    848.                                     /*       XDef   ActiveSprites,InactiveSprites,PreservedSprites                     */
    849.                                     /*       XDef   PreviousSprite,PendingSprites                                       */
    850.                                     /*       If   PlotRestore=Yes                                                      */
    851.                                     /*       XDef   RestoreSeen,RestoreUnseen,RestoreStack                              */
    852.                                     /*       EndC                                                                     */
    853.                                     /*       XDef   RainbowSeen_1,RainbowUnseen_1                                       */
    854.                                     /*       XDef   RainbowSeen_2,RainbowUnseen_2                                       */
    855.                                     /*       XDef   RainbowOffset                                                      */
    856.                                     /*       XDef   ShadowPalette,GemPalette,LegendPalette                              */
    857.                                     /*       XDef   PlotPriority                                                      */
    858.                                     /*       XDef   CollisionX,CollisionY,CollisionIDList                              */
    859.                                     /*                                                                               */
    860.                                     /*       XDef   GetSpriteBlocks,PlayerOne,PlayerTwo                                 */
    861.                                     /*       XDef   SetScreenAddr,ScreenAddresses                                       */
    862.                                     /*       XDef   SetSpriteReady,SpriteReady                                          */
    863.                                     /*       XDef   RestoreBack,PrimeAll                                                */
    864.                                     /*       XDef   ClearScreen,ClearGameScreen,CopyScreen                              */
    865.                                     /*       XDef   InitiateSprite,InitiateBlock,HexPrint                              */
    866.                                     /*       XDef   SpriteClear,SpriteHandler,Feedback                                 */
    867.                                     /*       XDef   AutoAnimate,PlotSchedule                                          */
    868.                                     /*       XDef   PlotCollision,UnplotCollision,ReadCollision                        */
    869.                                     /*       XDef   FadeIn,FadeOut,FadeRun,FadeSpeed,SetColours                        */
    870.                                     /*       XDef   FadeColours,ToColours,FromColours                                 */
    871.                                     /*       XDef   PreparePlayer,CurrentPlayer,SetPlayers                              */
    872.                                     /*       XDef   LargeFrames,LargeFrameFree                                          */
    873.                                     /*       XDef   FirstLargeLeft,FirstLargeRight,FirstLarge                           */
    874.                                     /*       XDef   SmallFrames,SmallFrameFree                                          */
    875.                                     /*       XDef   FirstSmallLeft,FirstSmallRight,FirstSmall                           */
    876.                                     /*       XDef   PlayerStop                                                         */
    877.                                     /*       XDef   WalkCheckX,WalkSpeeds,FallCheckY,OriginUnder                        */
    878.                                     /*       XDef   RideCheckX,IdentifyCell,IDRainbowY                                 */
    879.                                     /*       XDef   RainbowY,IdentifyCellLeft,IdentifyCellRight                        */
    880.                                     /*       XDef   CrashCheck,DisplayLives,DisplayGems                                 */
    881.                                     /*       XDef   ExecuteAnim,ActivateAMP                                             */
    882.                                     /*       XDef   PlayerStencil,Statistics,BenchPlayer,JumpUpSpeed                  */
    883.                                     /*       XDef   ContinuePlayer,ReverseWord,GlobalCollision                        */
    884.                                     /*       XDef   DemoPlayer                                                         */
    885.                                     /*       XDef   NextIsland                                                         */
    886.                                     /*                                                                               */
    887.                                     /* ;---------------------------------------------------------------------------   */
    888.                                     /* ;                                                                              */
    889.                                     /* ; Globals                                                                     */
    890.                                     /* ;                                                                              */
    891.                                     /* ;---------------------------------------------------------------------------   */
    892.                                     /*                                                                               */
    893.                                     /*       Section Text                                                            */
    894.                                     /*                                                                               */
    895. SWORD SpriteOldX=0;
    896.                                     /* ScreenBase   dc.l   0      ; Address of screen to access                           */
    897.                                     /* ScreenSeen   dc.l   0      ; Address of viewed screen                              */
    898.                                     /* ScreenUnseen   dc.l   0      ; Address of unseen screen                           */
    899. UBYTE *ScreenSaved=0; /*   dc.l   0      ; Address of saved background                           */
    900. SPRITE *ActiveSprites;               /*   dc.l   0      ; Active sprite link list head                     */
    901. SPRITE *PendingSprites;               /*   dc.l   0      ; Newly initiated sprites                           */
    902. SPRITE *InactiveSprites;            /* dc.l   0      ; Inactive sprite link list head                     */
    903. SPRITE *PreservedSprites;            /* dc.l   0      ; Temporarily suspended list                     */
    904. SPRITE *PreviousSprite;               /*   dc.l   0      ; Deleted sprite previous entry                     */
    905. SWORD ActiveSpriteCount;
    906.  
    907. STATSDATA Statistics[]=
    908. {
    909.   {0,3},          /* RubyRing       -  Shoes                               */
    910.   {0,3},          /* CrystalRing    -  Red jars                            */
    911.   {0,3},          /* AmethystRing   -  Yellow jars                         */
    912.   {0,77},         /* Necklace       -  Rounds                              */
    913.   {0,33},         /* Special        -  Games                               */
    914.   {0,30},         /* Pentagram      -  Completions                         */
    915.   {0,2},          /* HolyComet      -  Crosses                             */
    916.   {0,3},          /* RainbowCross   -  Any lamps                           */
    917.   {0,2},          /* ThunderCross   -  Any rings                           */
    918.   {0,27},         /* RainbowDrug    -  Rounds                              */
    919.   {0,10},         /* MagicalCape    -  Player deaths                       */
    920.   {0,15},         /* HolyCup        -  Any jars                            */
    921.   {0,6},          /* PeacockFeather -  Hurry messages                      */
    922.   {0,6},          /* CopperRod      -  Copper crowns                       */
    923.   {0,8},          /* SilverRod      -  Silver crowns                       */
    924.   {0,10},         /* GoldenRod      -  Gold crowns                         */
    925.   {0,2},          /* Balloon        -  Any rods                            */
    926.   {0,8},          /* BookOfWings    -  Shoes                               */
    927.   {0,3},          /* Clock          -  Tiaras                              */
    928.   {0,120},        /* BlueTiara      -  Enemies crushed                     */
    929.   {0,20},         /* GreenTiara     -  Enemies killed by fairy             */
    930.   {0,30},         /* RedTiara       -  Enemies with star                   */
    931.   {0,20},         /* Bell           -  Rounds                              */
    932.   {0,2},          /* StarRod        -  Capes                               */
    933.   {0,20},         /* RedLamp        -  Red stars                           */
    934.   {0,10},         /* YellowLamp     -  Yellow stars                        */
    935.   {0,5},          /* BlueLamp       -  Holy cups                           */
    936.   {0,7},          /* RedWand        -  Red diamonds                        */
    937.   {0,7},          /* OrangeWand     -  Orange diamonds                     */
    938.   {0,7},          /* YellowWand     -  Yellow diamonds                     */
    939.   {0,7},          /* GreenWand      -  Green diamonds                      */
    940.   {0,7},          /* BlueWand       -  Blue diamonds                       */
    941.   {0,7},          /* IndigoWand     -  Indigo diamonds                     */
    942.   {0,7},          /* PurpleWand     -  Purple diamonds                     */
    943.   {0,2},          /* RedHolyWater   -  Red wands                           */
    944.   {0,2},          /* OrangeHolyWat  -  Orange wands                        */
    945.   {0,2},          /* YellowHolyWat  -  Yellow wands                        */
    946.   {0,2},          /* GreenHolyWater -  Green wands                         */
    947.   {0,2},          /* BlueHolyWater  -  Blue wands                          */
    948.   {0,2},          /* IndigoHolyWat  -  Indigo wands                        */
    949.   {0,2},          /* PurpleHolyWat  -  Purple wands                        */
    950.   {0,2}           /* Key            -  Feathers                            */
    951. };
    952.  
    953.  
    954. PLAYER *CurrentPlayer=NULL;
    955. PLAYER *BenchPlayer=NULL;
    956.  
    957. UDWORD BCDScore=0;
    958. SPRITE *PlotPriority[16];
    959.                          
    960. SWORD Feedback=0;    /* AMP communication data */
    961.  
    962. #define MaximumSprites   100            /* System maximum sprites          */
    963. #define CollisionGridX (CharacterX*2)  /* Map size for collision matrix    */
    964. #define CollisionGridY (CharacterY*2)
    965.  
    966. UDWORD BonusLives[]=
    967. {
    968.    0x00010000,    /* First at 100,000 */
    969.    0x00100000,    /* Second at 1,000,000 */
    970.    0xffffffff     /* High values! No more. */
    971. };
    972. PLAYER PlayerStencil=                                                      
    973. {                                  
    974.   0, /* .Score      dc.l   $00000000                                                   */
    975.   0, /* .NextLife   dc.w   0      ; Index into bonus lives table                        */
    976.   3, /* .Lives      dc.w   3                                                            */
    977.   0, /* .High      dc.l   0                                                               */
    978.   0x00999999, /* .Maximum   dc.l   $00999999                                                      */
    979.   0, /* .Enhancements   dc.w   0                                                         */
    980.   0, /* .Permanent   dc.w   0                                                            */
    981.   0, /* .Island    dc.w   0      ; 0-9                                                      */
    982.   0, /* .Round      dc.w   0      ; 0-3                                                   */
    983.   0, /* .Stage      dc.w   0      ; 0-3                                                   */
    984.   0,0, /* .BusyUsed   dc.b   0,0                                                         */
    985.   0, /* .Diamonds   dc.w   0      ; Small diamonds collected                              */
    986.   0, /* .BigDiamonds   dc.w   0                                                         */
    987.   0, /* .Mirrors   dc.w   0                                                               */
    988.   0, /* .Secrets   dc.w   0                                                               */
    989.   0, /* .NextSpecial   dc.w   0      ; Next special to release                           */
    990.   0,80, /* .HiddenFruit   dc.b   0,80      ; Hidden fruit image number                     */
    991.   0,80, /* .NormalKills   dc.b   0,80      ; Enemy kills image number                        */
    992.   0,8, /* .SpecialIndex   dc.b   0,8      ; Next feature                                    */
    993.   0,3, /* .Feature   dc.b   0,3      ; Enemy kill count                                    */
    994.   1, /* .Number    dc.w   1      ; Player number, 1 or 2                                    */
    995.   0, /* .Difficulty   dc.w   0      ; multiples of 4, max. 28                              */
    996.   0, /* .Control   dc.w   0      ; Control method                                          */
    997.   0
    998. };
    999.  
    1000. /*                                                                               */
    1001. PLAYER PlayerOne,PlayerTwo;
    1002.  
    1003. /* ;---------------------------------------------------------------------------   */
    1004. /* ;                                                                              */
    1005. /* ; Collision system data area.                                                 */
    1006. /* ; SpriteClear is responsible for clearing the area between CollisionStart      */
    1007. /* ; and CollisionEnd. X overspill areas are present as rainbows can project      */
    1008. /* ; off the side of the screen. Some Y overspill also present to cover            */
    1009. /* ; any mishaps.                                                                  */
    1010. /* ;                                                                              */
    1011. /* ;---------------------------------------------------------------------------   */
    1012. SPRITE *CollisionIDList[32];  
    1013.  
    1014. typedef struct COLLISION {
    1015. UDWORD Start[64*2];        /* X overspill left                            */
    1016. UDWORD X[CollisionGridX];  /* Collision grid size, to 4 pixel             */
    1017. UDWORD XOSR[64*2];         /* X overspill right                           */
    1018. UDWORD YOST[32*2];         /* Y overspill top                             */
    1019. UDWORD Y[CollisionGridY];  /* resolution.                                 */
    1020. UDWORD YOSB[32*2];         /* Y overspill bottom                          */
    1021. } COLLISION;
    1022.                                     /* CollisionEnd                                                                  */
    1023. COLLISION CollTable;
    1024. #define CollisionX (&CollTable.X[0])
    1025. #define CollisionY (&CollTable.Y[0])
    1026. /* ;---------------------------------------------------------------------------   */
    1027.  
    1028.  
    1029. UBYTE Diamond  [130];
    1030.  
    1031. /***************************************************************************
    1032. InitAngles
    1033.    constructs x+y secant tables
    1034. *****************************************************************************/
    1035. void  InitAngles(void)
    1036. {
    1037. SWORD XPos,YPos;
    1038. UBYTE    Angle ;
    1039. UBYTE    Last ;
    1040. UWORD  Value;
    1041. UWORD  Entry;
    1042. UWORD  Count;
    1043.   for (Value = 0; Value < 130 ; Value ++)
    1044.       Diamond [Value] = 255;
    1045.  
    1046.   for (Angle= 0; Angle < 128; Angle ++ )
    1047.   {  
    1048.       _SinCos (Angle) ;
    1049.         if (Sine14<0)
    1050.             YPos = 0-Sine14;
    1051.         else
    1052.             YPos = Sine14;
    1053.  
    1054.         if (Cosine14<0)
    1055.             XPos = 0-Cosine14;
    1056.         else
    1057.             XPos = Cosine14;
    1058.  
    1059.         Value = (XPos + YPos ) ;
    1060.         Value = 64 + ( Cosine14  / (Value >> 6 )) ;
    1061.    
    1062.         Diamond [Value] = Angle;
    1063.   }
    1064.       /*** fill in gaps ***/
    1065.       Last = 128;
    1066.       Diamond [0] = 128;
    1067.       Diamond [128] = 0 ;      
    1068.       for (Value = 0; Value < 130 ; Value ++)
    1069.       {
    1070.         Angle= Diamond [Value];
    1071.         if (Angle == 255) {
    1072.             Count = 0;
    1073.           for (Entry = Value; (Entry < 130) && (Diamond [Entry] == 255); Entry++)
    1074.               {
    1075.               Angle = Diamond [Entry];
    1076.               Diamond [Entry]   = Last;
    1077.               Count+=1;
    1078.               }
    1079.             Last= Diamond [Entry];  /* get next value to back copy */
    1080.             Count = Count >> 1;
    1081.             if (Count >0) {
    1082.               Entry -= Count;
    1083.                 for (Value= Entry   ; Count > 0 ; Value ++)
    1084.                     {
    1085.                         Count -= 1;
    1086.                         Diamond [Value] = Last;
    1087.                     }
    1088.             }
    1089.          }
    1090.          Last = Diamond [Value];
    1091.       }
    1092.  
    1093. }
    1094.  
    1095.  
    1096. /***************************************************************************
    1097. GetAngle(SWORD X,SWORD Y)
    1098. looks up angles
    1099. *****************************************************************************/
    1100. UWORD GetAngle(SWORD X,SWORD Y)
    1101. {
    1102. SWORD XPos;
    1103. SWORD YPos;
    1104. SDWORD Value;
    1105. UWORD Angle;
    1106.  
    1107.     if (X<0)
    1108.         XPos = 0-X;
    1109.     else
    1110.         XPos = X;
    1111.  
    1112.     if (Y<0)
    1113.         YPos = 0-Y;
    1114.     else
    1115.         YPos = Y;
    1116.  
    1117.     Value = (XPos +YPos);
    1118.     if (Value>0)
    1119.     {
    1120.         Value = (( X << 6) / Value)+64;
    1121.         Angle = (Diamond [Value]);
    1122.         if (Y<0)
    1123.             Angle = 0-Angle;
    1124.     }
    1125.     else
    1126.     {
    1127.         Angle = 0 ;  /*for x y zero case */
    1128.     }
    1129.     return (Angle);
    1130. }
    1131.  
    1132. /***************************************************************************
    1133. GetDistance(SWORD X,SWORD Y)
    1134. calcs distance using |X| +|Y|  halfing lowest factor
    1135. *****************************************************************************/
    1136. UDWORD GetDistance(SWORD X,SWORD Y)
    1137. {
    1138.  
    1139.         if (X<0)         /* make each positive */
    1140.             X = 0-X;
    1141.         if (Y<0)
    1142.             Y = 0-Y;
    1143.         if  (X>Y)        /* half smallest component */
    1144.             Y>>=1;
    1145.         else
    1146.             X>>=1;
    1147.         return (X+Y);
    1148. }
    1149.  
    1150. /*--------------------------------------------------------------------------
    1151. SinCos
    1152. ;
    1153. ; Calculate Sine and Cosine of binary angle
    1154. ;
    1155. ;   Expects     d0 angle
    1156. ;
    1157. ;   Returns     d0 sine {14 bp}
    1158. ;           d1 cosine {14 bp}
    1159. ;KH NOW defined as a macro - assumes d0,d1 defined as SWORDS
    1160. ;--------------------------------------------------------------------------*/
    1161. #define SinCos(angle)  _SinCos(angle); d0=Sine14; d1=Cosine14;
    1162.  
    1163.  
    1164. /* -------------------------------------------------------------------------
    1165. AngleDistance
    1166. ;
    1167. ; Angle and Distance Calculator
    1168. ;
    1169. ;   Expects     d0,d1   W   Vector
    1170. ;
    1171. ;   Returns     d0  W   Binary angle
    1172. ;           d1  W   Distance
    1173. ;
    1174. ;KH NOW defined as a macro - assumes d0,d1 defined
    1175. ;------------------------------------------------------------------------- */
    1176. #define AngleDistance(x,y)   d1=GetDistance(x,y); d0=GetAngle(x,y);
    1177.  
    1178.  
    1179. /* ------------------------------------------------------------------------ */
    1180.  
    1181.  
    1182. /* ---------------------------------------------------------------------------
    1183. ContinuePlayer
    1184. --------------------------------------------------------------------------- */
    1185. void ContinuePlayer(void)
    1186. {
    1187.   CurrentPlayer->PlayerPerm |= Continued;
    1188.  
    1189.   PreparePlayer(CurrentPlayer,sizeof(CONTINUEPLAYER),CurrentPlayer->PlayerNumber);  /* 12=number of bytes to copy*/
    1190.  
    1191.   GameFlags |= ScoreRefresh;
    1192.   ScoreMaintain();
    1193.  
    1194. }
    1195. /* ---------------------------------------------------------------------------
    1196. SetPlayers
    1197. --------------------------------------------------------------------------- */
    1198. void SetPlayers(void)
    1199. {
    1200.   BenchPlayer= &PlayerTwo;
    1201.  
    1202.   if (Players == 1)
    1203.   {
    1204.     PlayerTwo.PlayerLives = (-1);
    1205.  
    1206.   }
    1207.   else
    1208.   {
    1209.     PreparePlayer(&PlayerTwo,sizeof(PLAYER),2);  /* a0,d0,d1 */
    1210. //  PlayerTwo.PlayerControl = ControlMethod2;
    1211.     PlayerTwo.PlayerScoreX = 29*8;
    1212.     GameFlags |= ScoreRefresh;
    1213.     ScoreMaintain();
    1214.   }
    1215.  
    1216.  
    1217.   PreparePlayer(&PlayerOne,sizeof(PLAYER),1);  /* a0,d0,d1 */
    1218. //  PlayerOne.PlayerControl = ControlMethod1;
    1219.   PlayerOne.PlayerScoreX = 1*8;
    1220.   GameFlags |= ScoreRefresh;
    1221.   ScoreMaintain();
    1222.  
    1223. }
    1224.  
    1225.  
    1226.  
    1227. /* ---------------------------------------------------------------------------
    1228. DemoPlayer
    1229. --------------------------------------------------------------------------- */
    1230. void DemoPlayer(void)
    1231. {
    1232.   PreparePlayer(&PlayerOne,sizeof(PLAYER),1);  /* a0,d0,d1 */
    1233.   PlayerOne.PlayerScoreX = 1*8;
    1234.   GameFlags |= ScoreRefresh;
    1235.   ScoreMaintain();
    1236. }
    1237.  
    1238. /* ---------------------------------------------------------------------------
    1239. PreparePlayer
    1240. --------------------------------------------------------------------------- */
    1241. void PreparePlayer(PLAYER *a0,UWORD d0,UWORD d1)
    1242. {
    1243.   PLAYER *a1;
    1244.   UWORD PlayerControl;
    1245.  
    1246.   CurrentPlayer = a0;
    1247.   a1= &PlayerStencil;
    1248.  
    1249.   PlayerControl = a0->PlayerControl;    /* Preserve this */
    1250.   memcpy(a0,a1,d0);  /* copy d0 bytes from stencil */
    1251.   a0->PlayerNumber = d1;
    1252.   a0->PlayerBusy = d1-1;
    1253.   a0->PlayerUsed = d1+1;
    1254.   a0->PlayerControl = PlayerControl;    /* Restore it */
    1255.  
    1256.   AddStatistic(_Stats33rd);
    1257. }
    1258.                                  
    1259. /* -------------------------------------------------------------------------  
    1260. GetSpriteBlocks
    1261. ;                                                                            
    1262. ; Allocate all required sprite blocks                                        
    1263. ; and build them into a linked list with InactiveSprites as header                                                                            
    1264. ;-------------------------------------------------------------------------   */
    1265. void GetSpriteBlocks()
    1266. {
    1267.   SysError *Err=NULL;
    1268.   int i;
    1269.   SPRITE *Current;
    1270.  
    1271.   if((Err=MemoryClaim(MainMem,MaximumSprites*sizeof(SPRITE),
    1272.                          &SpBlocks,NULL,MEM_FIXED_ADDRESS,"SP:INACTIVE")) == NULL)
    1273.     {
    1274.     Current=(SPRITE *)SpBlocks->Address;
    1275.     InactiveSprites=NULL;      
    1276.  
    1277.     for (i=0 ; i<MaximumSprites ;i++)
    1278.       {                              
    1279.       Current->SpriteLink = InactiveSprites;
    1280.       Current->SpriteID = 0;
    1281.       InactiveSprites = Current++;
    1282.       }                            
    1283.     }
    1284. }
    1285.  
    1286. /* ------------------------------------------------------------------------
    1287. SetSpriteReady                                                                  
    1288. ------------------------------------------------------------------------ */
    1289. void SetSpriteReady(void)
    1290. {
    1291.    SpriteReady.SpriteFlags    = 0;        /* Required  */
    1292.    SpriteReady.SpriteLife     = -0x8000;  /* Required  */
    1293.    SpriteReady.SpritePlot     = _NullPlot;/* Safety    */
    1294.    SpriteReady.SpritePriority = 0;        /* Safety    */
    1295.    SpriteReady.SpriteOffset   = 0,        /* Required  */
    1296.    SpriteReady.SpriteParent   = 0;        /* Required  */
    1297.    SpriteReady.SpriteBase2    = 0;        /* Required  */
    1298.    SpriteReady.SpriteDisplace = 0;        /* Safety    */
    1299.    SpriteReady.SpriteAnimate  = (-1);     /* Required  */
    1300.    SpriteReady.SpriteARC      = 0;        /* Required  */
    1301.    SpriteReady.SpriteMRepeat  = 0;        /* Required  */
    1302.    SpriteReady.SpriteMPC      = 0;        /* Required  */
    1303.    SpriteReady.SpriteAIRQ     = 0x7fff;   /* Required  */
    1304.    SpriteReady.SpriteMIRQ     = 0x7fff;   /* Required  */
    1305.    SpriteReady.SpriteLVector  = 0;        /* Required  */
    1306.    SpriteReady.SpriteCID      = (-1);     /* Required  */
    1307.    SpriteReady.SpriteCMask    = 0x0000;   /* Safety    */
    1308.    SpriteReady.SpriteCResult  = 0;        /* Required  */
    1309.    SpriteReady.SpriteCSize    = 0;        /* Safety    */
    1310.    SpriteReady.SpriteClass    = 0;        /* Safety    */
    1311.                  
    1312. }
    1313.  
    1314.  
    1315. /* ;---------------------------------------------------------------------------   */
    1316. /* ;--------------------------------------------------------------------------
    1317. HexPrint                      
    1318. ;                                                                              
    1319. ; Convert a hex value 0-99 into two ASCII characters and store them for        
    1320. ; printing, with zero suppression on the top digit.                          
    1321. ;                                                                              
    1322. ; Requirements: d0 - word value to convert                                  
    1323. ;      d1 - Zero suppression pad character in ASCII or control code          
    1324. ;      a0 - location to store result at                                        
    1325. ;xx      Returns: a0 - unchanged                                              
    1326. ;                                                                            
    1327. ; Note that the result is stored as bytes and so a0 may be passed as an        
    1328. ; odd address.                                                                
    1329. ;                                                                            
    1330. ;---------------------------------------------------------------------------   */
    1331. void HexPrint(UBYTE *a0,UWORD d0,UWORD d1)
    1332. {
    1333.   UWORD Temp;
    1334.  
    1335.   Temp=d0/10;
    1336.   if (Temp==0)
    1337.     Temp=d1;         /* zero supress */
    1338.   else
    1339.     Temp|=0x30;
    1340.   *a0++ = Temp;       /* tens */
    1341.  
    1342.   *a0 = (d0%10)|0x30;    /* units */
    1343. }
    1344.  
    1345. /* ;-------------------------------------------------------------------------
    1346. SpriteClear                                                                  
    1347. ;                                                                            
    1348. ; Kill all allocated or pending sprites by moving them to the inactive list,
    1349. ; clear the collision matrix, and the collision ID list,                    
    1350. ; deallocate all active rainbow and fruit blocks,                            
    1351. ; clear all 'Declared' blocks.                                              
    1352. ;                                                                            
    1353. ;-------------------------------------------------------------------------- */
    1354. void SpriteClear(void)
    1355. {
    1356.   int i;
    1357.   SPRITE *a1;
    1358.  
    1359.   GameFlags &= ~SuspendSprites;
    1360.  
    1361.   memset(&CollTable,0,sizeof(COLLISION)); /* clear entire collision table */
    1362.   for (i=0;i<32;i++)
    1363.     CollisionIDList[i]=0;                 /* clear ID List */
    1364.  
    1365.   InactiveRainbowCount=12;
    1366.   InactiveFruitCount=22;
    1367.  
    1368. /* Fruit: */
    1369.   {
    1370.     FRUIT *a0,*a1,*a2,*a3;
    1371.     while (1)
    1372.     {
    1373.        a1=ActiveFruit.FruitFLink;
    1374.        a0= (&ActiveFruit);
    1375.        if (a1 == a0)
    1376.           break;
    1377.        a2=a1->FruitFLink;
    1378.        a3=a1->FruitBLink;
    1379.        a3->FruitFLink = a2;
    1380.        a2->FruitBLink = a3;
    1381.  
    1382.        a0= (&InactiveFruit);
    1383.        a1->FruitFLink=a0->FruitFLink;
    1384.        a0->FruitFLink=a1;
    1385.     }
    1386.   }
    1387. /* Rainbow: */
    1388.   {
    1389.     RAINBOW *a0,*a1,*a2,*a3;
    1390.     while (1)
    1391.     {
    1392.        a1=ActiveRainbows.RainbowFLink;
    1393.        a0= (&ActiveRainbows);
    1394.        if (a1 == a0)
    1395.           break;
    1396.        a2=a1->RainbowFLink;
    1397.        a3=a1->RainbowBLink;
    1398.        a3->RainbowFLink = a2;
    1399.        a2->RainbowBLink = a3;
    1400.  
    1401.        a0= (&InactiveRainbows);
    1402.        a1->RainbowFLink=a0->RainbowFLink;
    1403.        a0->RainbowFLink=a1;
    1404.     }
    1405.   }
    1406.  
    1407. /* .Control */
    1408.   for (i=0;i<NumberOfCBlocks;i++)
    1409.     ControlBlocks[i]=0;
    1410.  
    1411. /* .Sprite */
    1412.   ActiveSpriteCount = 0;
    1413.   while ((a1 = ActiveSprites))
    1414.   {
    1415.     ActiveSprites = a1->SpriteLink;
    1416.     a1->SpriteLink = InactiveSprites;
    1417.     InactiveSprites = a1;
    1418.     a1->SpriteID=0;
    1419.   }
    1420.  
    1421. /* .Pending */
    1422.   while ((a1 = PendingSprites))
    1423.   {
    1424.     PendingSprites = a1->SpriteLink;
    1425.     a1->SpriteLink = InactiveSprites;
    1426.     InactiveSprites = a1;
    1427.     a1->SpriteID=0;
    1428.   }
    1429. }
    1430.  
    1431.  
    1432. AMPDATA d2;       /* NB Error value returned from MRoutines */
    1433. SPRITE *a2;
    1434. AMPDATA *ad;
    1435. AMPDATA *a3;
    1436.  
    1437. /* ;---------------------------------------------------------------------------
    1438. SpriteHandler
    1439. ;                                                                              
    1440. ; Main manoeuvre-program-driven object handler. Updates all active objects      
    1441. ; and queues them according to their display priority. The PlotSchedule        
    1442. ; routine will plot all objects once they are 'sorted' into priority            
    1443. ; sequence.                                                                    
    1444. ;                                                                              
    1445. ;---------------------------------------------------------------------------   */
    1446. void SpriteHandler(void)
    1447. {
    1448.   AMPDATA *Next;
    1449.   AMPDATA Com;
    1450.   UDWORD d0;
    1451.  
    1452.   AMPDATA d3;
    1453.   AMPDATA d4;
    1454.   AMPDATA d5;
    1455. /*AMPDATA d6;    Removed 19/4/96 - AB, optimised out */
    1456.   void (*a4)();
    1457.  
    1458.   memset(PlotPriority,0,16*sizeof(SPRITE *));  /* zeroise PlotPriority array */
    1459.   PreviousSprite = (SPRITE *)&ActiveSprites;
    1460.   a2 = ActiveSprites;
    1461.  
    1462.   while (a2 != NULL)
    1463.   {
    1464.     if (((GameFlags & SuspendSprites) != 0) &&
    1465.        ((a2->SpriteFlags & SuspendExempt) == 0))
    1466.         {                                               /* If suspend on and not exempt */
    1467.       goto Plot;                                    /* then plot only, no action        */
    1468.         }
    1469.  
    1470.     UnplotCollision();            /* .Collision */
    1471.      
    1472.     if (a2->SpriteCResult & a2->SpriteCMask)
    1473.       {
    1474.       a2->SpriteMPC = a2->SpriteCVector;
    1475.       a2->SpriteMRepeat = 0;
    1476.       goto Instruct;
    1477.       }
    1478.  
    1479.     if (a2->SpriteLife >= 0)
    1480.       {
    1481.       a2->SpriteLife--;
    1482.       if ((a2->SpriteLife < 0) && (a2->SpriteLVector != 0))
    1483.         {
    1484.         a2->SpriteMPC = a2->SpriteLVector;
    1485.         a2->SpriteMRepeat = 0;
    1486.         goto Instruct;
    1487.         }
    1488.       }
    1489.  
    1490.     if (a2->SpriteARC >= a2->SpriteAIRQ)
    1491.       {
    1492.       a2->SpriteMPC = a2->SpriteAVector;
    1493.       a2->SpriteMRepeat = 0;
    1494.       }
    1495. Instruct:                           /* Manoeuvre program                  */
    1496.     if (a2->SpriteMRepeat)
    1497.       goto More;
    1498.     Next=a2->SpriteMPC;
    1499. /* NextInstruct: */
    1500.     Com = *Next;
    1501.     if (Com < 0)
    1502.       {
    1503.       a2->SpriteMSavePC = Next;
    1504.       a2->SpriteMRepeat = 1;
    1505.       goto More;
    1506.       }
    1507.  
    1508.     if ((Com & (1<<13)))
    1509.       Com = 1 + ((Com & 0x03ff) & RandNum());
    1510.     a2->SpriteMRepeat = Com;
    1511.  
    1512. More:
    1513.  
    1514.     a3 = a2->SpriteMSavePC;
    1515.     d3 = *(a3+0);
    1516. /*
    1517.     d4 = *(a3+1);
    1518.     d5 = *(a3+2);
    1519.     d6 = *(a3+3);
    1520. */
    1521.     a4 = AMPList[ ((d3 & 0x03fc)>>2) ];  /* address of routine */
    1522.  
    1523.  
    1524.     if (a2->SpriteMRepeat & (1<<14))      /* Forever?  */
    1525.       goto Remaining;                      
    1526.  
    1527.     if (--a2->SpriteMRepeat)
    1528.       goto Remaining;              
    1529.  
    1530.     if (d3 < 0)
    1531.       {
    1532.       a3 = a2->SpriteMPC;
    1533.       a2->SpriteMPC += 1+(d3 & 0x0003);
    1534.       }
    1535.     else
    1536.       {
    1537.       a2->SpriteMPC ++;        /* NB ++ will advance by 2 bytes! */
    1538.       }
    1539. Remaining:
    1540.  
    1541. /* =================================================================== */
    1542.     d2=0;
    1543.     switch ((d3 & 0x03fc)>>2)
    1544.     {
    1545.        case _Delay: /* MDelay */
    1546.        {
    1547.           break;
    1548.        }
    1549.        case _Goto:  /* Mgoto */
    1550.        {
    1551.           d4 = *(a3+1);
    1552.           a2->SpriteMPC = a3 + (d4/2);   /* NB d4 is byte offset /2 for AMPDATA offset */
    1553.           a2->SpriteMSavePC = a2->SpriteMPC;
    1554.           break;
    1555.        }
    1556.        case _Activate: /* MActivate */
    1557.        {
    1558.           d4 = *(a3+1);
    1559.           ActivateAMP(a3 + (d4/2));
    1560.           break;
    1561.        }
    1562.        case _Animate:  /* MAnimate */
    1563.        {
    1564.           UBYTE cd3;
    1565.  
    1566.           d4 = *(a3+1);
    1567.           d5 = *(a3+2);
    1568.           cd3 = d3 & 0x0003;
    1569.           if (cd3 <2 )
    1570.              a2->SpriteAnimate = d4;      /* Stop/start auto animation      */
    1571.           else
    1572.           {
    1573.              if (cd3 == 3)
    1574.              {
    1575.                 a2->SpriteBase = d5;
    1576.                 a2->SpriteBase2= 0;
    1577.              }
    1578.              a2->SpriteList = ((UBYTE *)a3) + d4;  /* new list addr */
    1579.              a2->SpriteOffset=0;
    1580.              a2->SpriteAnimate=0;            /* force read */
    1581.  
    1582.           }
    1583.           break;
    1584.        }
    1585.        case _AVector:  /* MAVector */
    1586.        {
    1587.           d4 = *(a3+1);
    1588.           d5 = *(a3+2);
    1589.           a2->SpriteAVector = a3+(d5>>1);
    1590.           a2->SpriteAIRQ = d4;
    1591.           break;
    1592.        }
    1593.        case _MVector:  /* MMVector */
    1594.        {
    1595.           d4 = *(a3+1);
    1596.           d5 = *(a3+2);
    1597.           a2->SpriteMVector = a3+(d5>>1);
    1598.           a2->SpriteMIRQ = d4;
    1599.           break;
    1600.        }
    1601.        case _LVector:  /* MLVector */
    1602.        {
    1603.           d4 = *(a3+1);
    1604.           if (d4)
    1605.             a2->SpriteLVector = a3+(d4>>1);
    1606.           else
    1607.             a2->SpriteLVector = 0;
    1608.           break;
    1609.        }
    1610.        case _CVector:  /* MCVector */
    1611.        {
    1612.           d4 = *(a3+1);
    1613.           d5 = *(a3+2);
    1614.           if (d5)
    1615.             {   /* CVECTOR ON */
    1616.             a2->SpriteCVector = a3 + (d5>>1);
    1617.             a2->SpriteCMask = d4;
    1618.             }
    1619.           else
    1620.             {   /* 0 if CVECTOR OFF */
    1621.             a2->SpriteCVector = NULL;
    1622.             a2->SpriteCMask = 0;
    1623.             }
    1624.           break;
    1625.        }
    1626.        case _Transform:   /* MTransform */
    1627.        {
    1628.           d4 = *(a3+1);
    1629.           InitiateBlock(a2,a3+(d4>>1),sizeof(SPRITE));
    1630.           break;
    1631.        }
    1632.        case _GDOMarker:  /* GDOMarker */
    1633.        {
    1634.           break;
    1635.        }
    1636.  
    1637.  
    1638.        default:
    1639.       {
    1640.         ad = a3+1;
    1641.         a4();                      /* Execute instruction */
    1642.         break;
    1643.       }
    1644.     }
    1645. /* =================================================================== */
    1646.  
    1647.     if (a2->SpriteMIRQ == d2)   /* Check return code   */
    1648.       {
    1649.       a2->SpriteMPC = a2->SpriteMVector;
    1650.       a2->SpriteMRepeat = 0;
    1651.       goto Instruct;
    1652.       }
    1653.  
    1654.     if (!(d3 & (1<<14)))          /* Check delay bit */
    1655.       goto Instruct;              /* Unset, do next instruction   */
    1656.  
    1657.     if (a2->SpriteID)        /* Deleted if ID set to zero                        */
    1658.       goto Animate;
    1659.  
    1660. /* Delete: */
    1661.     PreviousSprite->SpriteLink = a2->SpriteLink;  /* unlink from active */
    1662.  
    1663.     a2->SpriteLink = InactiveSprites;
    1664.     InactiveSprites = a2;                         /* and link into inactive */
    1665.     ActiveSpriteCount--;
    1666.  
    1667.     a2=PreviousSprite;
    1668.     goto Next;
    1669.  
    1670. Animate:
    1671.     a2->SpriteARC = AutoAnimate(a2); /* Return code for next time */
    1672.     PlotCollision();
    1673.  
    1674. Plot:
    1675.  
    1676.     d0 = (a2->SpritePriority & 0x003c) >>2;   /* convert to index */
    1677.     a2->SpritePlotLink = PlotPriority[d0];
    1678.     PlotPriority[d0] = a2;
    1679.  
    1680. Next:
    1681.     PreviousSprite = a2;
    1682.     a2 = a2->SpriteLink;
    1683.   }
    1684. }
    1685.  
    1686.  
    1687.  
    1688.  
    1689.  
    1690. /****************************************************************************
    1691. PlotSchedule                                                                  
    1692.                                                                              
    1693.  Plot all objects queued into the sixteen priority link lists. Any objects  
    1694.  of the same priority will be plotted in last in, first out sequence. Each  
    1695.  object has its own designated plot method which are listed in the            
    1696.  PlotMethods table.                                                            
    1697.  
    1698. ****************************************************************************/      
    1699. void PlotSchedule(void)
    1700. {
    1701.   int i;
    1702.  
    1703.   PlotTimer++; /* used by flashing objects (see malternateplot) */
    1704.   InitPlotList();
    1705.  
    1706.   for (i=0;i<16;i++)    /* for each plot priority (up to 16 used!) */
    1707.   {
    1708.     a2=PlotPriority[i];
    1709.     while (a2)
    1710.     {
    1711.      
    1712.       switch (a2->SpritePlot)
    1713.       {
    1714.         case _FullPlot16:
    1715.         case _FullPlot32:
    1716.         case _AlignedPlot16:
    1717.         case _AlignedPlot32:
    1718.         case _TwoFullPlot32:
    1719.         case _TwoAlignedPlot32:
    1720.         case _FourFullPlot32:
    1721.         {
    1722.               FullPlot();
    1723.            break;
    1724.         }
    1725.         case _CutPlot16:
    1726.         case _CutPlot32:
    1727.         case _TwoCutPlot32:
    1728.         {
    1729.             CutPlot();
    1730.           break;
    1731.  
    1732.         }
    1733.         case _VLinePlot16:
    1734.         case _VLinePlot32:
    1735.         {
    1736.           VLinePlot();        
    1737.  
    1738.           break;
    1739.         }
    1740.         case _PlayerPlot32:
    1741.         {
    1742.             PlayerPlot();
    1743.           break;
    1744.         }
    1745.           case _RainbowPlot:                /* Ready for semi-trans on PSX */
    1746.           {
    1747.             RainbowPlot();
    1748.           break;
    1749.           }
    1750.       }
    1751.       a2=a2->SpritePlotLink;  
    1752.     }
    1753.   }
    1754.  
    1755.   PlotFrontDrop();
    1756.   FinishPlotList();
    1757.  
    1758. }
    1759.  
    1760.  
    1761. /* ;---------------------------------------------------------------------------
    1762. ExecuteAnim
    1763. ;  
    1764. ; As MAnimate but using a loaded resident animation list as the source            
    1765. ;                                                                          
    1766. ;-----------------------------------------------------------------------   */
    1767. void ExecuteAnim(UWORD d0)
    1768. {
    1769.  
    1770.   a2->SpriteList = (UBYTE *)(*(ResAMPs+d0));  /* new list addr */
    1771.   a2->SpriteOffset=0;
    1772.   a2->SpriteAnimate=0;            /* force read */
    1773. }
    1774.  
    1775. /* ;---------------------------------------------------------------------------
    1776. ActivateAMP
    1777. ;                                                                              
    1778. ; Single sprite activate from an AMP instruction. Faster and more readable      
    1779. ; than using ExecuteAnim on an Activate instruction.                          
    1780. ;                                                                              
    1781. ; Requirements: a0 - pointer to initiation block                              
    1782. ;      Expects: a2 - current sprite block pointer
    1783. ;      Returns: d2 - return code of 12 if failed, else unaffected              
    1784. ;      a1 - Pointer to new child sprite, or 0 if failed                          
    1785. ;                                                                              
    1786. ;--------------------------------------------------------------------------   */
    1787. SPRITE *ActivateAMP(AMPDATA *a0)
    1788. {
    1789.   SPRITE *a1;
    1790.  
    1791.   if (!(a1=InactiveSprites))
    1792.     {
    1793.     d2=12;
    1794.     return(a1);      /* ; No sprites available                              */
    1795.     }
    1796.   InactiveSprites = a1->SpriteLink;   /* remove first from inactive list */
    1797.  
    1798.   memcpy(a1,&SpriteReady,sizeof(SPRITE));
    1799.   a1->SpriteLink = a2->SpriteLink;
    1800.   a2->SpriteLink = a1;              /* insert into active list */
    1801.  
    1802.   a0=InitiateBlock(a1, a0, sizeof(SPRITE));
    1803.   ActiveSpriteCount++;
    1804.  
    1805.   a1->SpriteParent= a2;
    1806.   if (!a1->SpriteMPC)               /*    ; MPC set                                       */
    1807.     a1->SpriteMPC = a0;             /*    ; no, assume AMP follows                     */
    1808.   return(a1);
    1809. }
    1810. /* ;---------------------------------------------------------------------------
    1811. ActivateAMPRES
    1812. ;                                                                              
    1813. ; Single sprite activate from an AMP instruction. Faster and more readable      
    1814. ; than using ExecuteAnim on an Activate instruction.                          
    1815. ;                                                                              
    1816. ; Requirements: d0 - index of initiation block                              
    1817. ;      Expects: a2 - current sprite block pointer
    1818. ;      Returns: d2 - return code of 12 if failed, else unaffected              
    1819. ;      a1 - Pointer to new child sprite, or 0 if failed                          
    1820. ;                                                                              
    1821. ;--------------------------------------------------------------------------   */
    1822. SPRITE *ActivateAMPRES(UWORD d0)
    1823. {
    1824.   return(ActivateAMP(*(ResAMPs+d0)));
    1825. }
    1826.  
    1827.  
    1828.  
    1829. /* --------------------------------------------------------------------------  
    1830. AutoAnimate                                                                
    1831. ;                                                                          
    1832. ; Object auto animation system. Objects with a +ve animation count have    
    1833. ; it decremented. A zero result causes the next frame in the animation    
    1834. ; list to be fetched and added to the base frame to produce the actual    
    1835. ; animation frame.                                                        
    1836. ;   Rainbows also use this system but instead of the base and displacement
    1837. ; producing a frame number, the displacement is used to displace into the
    1838. ; colour list of the base frame for 'rotating rainbow effects'.          
    1839. ;                                                                          
    1840. ;---------------------------------------------------------------------------   */
    1841. UWORD AutoAnimate(SPRITE *Current)
    1842. {
    1843.   UWORD Ret=0;                       /* Return code assumed zero */
    1844.   UBYTE *a0;
    1845.   SWORD d0;
    1846.   UBYTE d1;
    1847.  
    1848.   if (Current->SpriteAnimate >= 0)
    1849.   {
    1850.     if (Current->SpriteAnimate > 0)
    1851.     {
    1852.       Current->SpriteAnimate--;
    1853.       return(Ret);
    1854.     }
    1855.  
    1856.     Ret = 4;                          /* Return code at least 4    */
    1857.     a0 = Current->SpriteList;
    1858.     d0 = Current->SpriteOffset;
    1859.  
    1860.     while (Ret < 16)                    /* Stop interpretting on disaster */
    1861.     {
    1862.       d1 = *(a0+d0);                     /* d1=frame or command    */
    1863.       if (!(d1 & 0x80))
    1864.         {  
    1865.         Current->SpriteDisplace = (d1);     /* extract frame offset */
    1866.  
    1867.         Current->SpriteFrame = Current->SpriteBase
    1868.                               + Current->SpriteBase2
    1869.                               + Current->SpriteDisplace;
    1870.         Current->SpriteAnimate = *(a0+d0+1);     /* extract frame count */
    1871.         Current->SpriteOffset = d0+2;
    1872.         return(Ret);
    1873.       }
    1874.  
    1875.       d0 +=2;
    1876.       switch (d1)
    1877.       {
    1878.         case EndList:
    1879.         {
    1880.           /* Restart list, rc=8         */
    1881.           d0 = 0;
    1882.           Ret = 8;
    1883.           break;
    1884.         }
    1885.         case NewList:
    1886.         {
    1887.           /* Switch list, rc=12         */
    1888.           a0 += d0 + *((SWORD *)(a0+d0));
    1889.           Current->SpriteList = a0;
    1890.           d0 = 0;
    1891.           Ret = 12;
    1892.           break;
    1893.         }
    1894.         case EndAuto:
    1895.         {
    1896.           /* Auto-animation off, rc=16   */
    1897.             Current->SpriteAnimate = (-1);
    1898.             Ret = 16;
    1899.           break;
    1900.         }
    1901.         case ALeft:
    1902.         {
    1903.             a2->SpriteDepth |= XFLIP;
    1904.           break;
    1905.         }
    1906.         case ARight:
    1907.         {
    1908.             a2->SpriteDepth &= ~XFLIP;
    1909.           break;
    1910.         }
    1911.         case AUp:
    1912.         {
    1913.             a2->SpriteDepth &= ~YFLIP;   /* Changed AB 8/3/96 */
    1914.           break;
    1915.         }
    1916.         case ADown:
    1917.         {
    1918.             a2->SpriteDepth |= YFLIP;    /* Changed AB 8/3/96 */
    1919.           break;
    1920.         }
    1921.  
    1922.       }
    1923.    
    1924.     }
    1925.    
    1926.   }
    1927.   return(Ret);
    1928. }
    1929.  
    1930.  
    1931.  
    1932.  
    1933.  
    1934. /* -----------------------------------------------------------------------
    1935. UnplotCollision                                                                
    1936. ;                                                                              
    1937. ; Collision matrix maintaining routines.                                      
    1938. ;                                                                              
    1939. ;------------------------------------------------------------------------- */
    1940. void UnplotCollision(void)
    1941. {
    1942.   SWORD d0,d2;
    1943.   SDWORD d1;
    1944.   UWORD *a0;
    1945.   UDWORD *a1;
    1946.  
    1947.   if ((d0=a2->SpriteCID) >=0 )   /* -ve = Read only, don't need to unplot as entry was not written */
    1948.   {
    1949.       d1 = (-1);
    1950.  
    1951.       d1 &= ~(1<<d0); /*        bclr.l  d0,d1 */
    1952.       a0 = (UWORD *)a2->SpriteCSize;
    1953.       a1 = CollisionX;
    1954.       d0 = a2->SpriteMasterX.W.H;
    1955.       d0 += *a0++;
    1956.       d0 &= 0xfffc;
    1957.       d2 = *a0++;
    1958.  
    1959.       a1 += (d0>>2); /* nb d0 is byte offset */
    1960.  
    1961.       do
    1962.       {
    1963.         *a1++ &= d1;    /* check this !!!!  and.l   d1,(a1)+ */
    1964.       } while (d2--);
    1965.  
    1966.       a1 = CollisionY;
    1967.       d0 = a2->SpriteMasterY.W.H;
    1968.       d0 += *a0++;
    1969.       d0 &= 0xfffc;
    1970.       d2 = *a0++;
    1971.       a1 += (d0>>2); /* nb d0 is byte offset */
    1972.       do
    1973.       {
    1974.         *a1++ &= d1;    /* check this !!!!  and.l   d1,(a1)+ */
    1975.       } while (d2--);
    1976.   }
    1977. }
    1978.  
    1979. /* -----------------------------------------------------------------------
    1980. PlotCollision                                                                
    1981. ;                                                                              
    1982. ; Collision matrix maintaining routines.                                      
    1983. ;                                                                              
    1984. ;------------------------------------------------------------------------- */
    1985. void PlotCollision(void)
    1986. {
    1987.   SWORD d0,d2;
    1988.   SDWORD d1;
    1989.   SWORD *a0;
    1990.   UDWORD *a1;
    1991.  
    1992.   d1 = 0;
    1993.   a2->SpriteCResult = d1;
    1994.   if ((d0 = a2->SpriteCID) >= 0)    /* -ve =  Read only, don't plot */
    1995.   {
    1996.      d1 |= (1<<d0);
    1997.      a0 = a2->SpriteCSize;
    1998.  
    1999.      a1 = CollisionX;
    2000.      d0 = a2->SpriteMasterX.W.H;
    2001.      d0 += *a0++;
    2002.      d0 &= 0xfffc;
    2003.      d2 = *a0++;
    2004.      a1 += (d0>>2);
    2005.     do
    2006.     {
    2007.       *a1++ |= d1;
    2008.     } while (d2--);
    2009.  
    2010.      a1 = CollisionY;
    2011.      d0 = a2->SpriteMasterY.W.H;
    2012.      d0 += *a0++;
    2013.      d0 &= 0xfffc;
    2014.      d2 = *a0++;
    2015.      a1 += (d0>>2);
    2016.     do
    2017.     {
    2018.       *a1++ |= d1;
    2019.     } while (d2--);
    2020.  
    2021.   }
    2022. }
    2023.  
    2024. /* -----------------------------------------------------------------------
    2025. ReadCollision                                                                
    2026. ;                                                                              
    2027. ; Collision matrix maintaining routines.                                      
    2028. ;                                                                              
    2029. ;------------------------------------------------------------------------- */
    2030. void ReadCollision(void)
    2031. {
    2032.   SWORD d0,d7;
    2033.   SDWORD d1,d2;
    2034.   SWORD *a0;
    2035.   UDWORD *a1;
    2036.  
    2037.   if (!(d0 = a2->SpriteCMask))
    2038.   {
    2039.     a2->SpriteCResult = d0;
    2040.     return;
    2041.   }
    2042.   /* Class specified, so CVector ready for collsion */
    2043.  
    2044.   d1 = 0;
    2045.   d2 = 0;
    2046.   if ((a0 = a2->SpriteCSize)) /*  Safety, no Collision if spritecsize 0 */
    2047.   {
    2048.      a1 = CollisionX;
    2049.      d0 = a2->SpriteMasterX.W.H;
    2050.      d0 += *a0++;
    2051.      d0 &= 0xfffc;
    2052.      d7 = *a0++;
    2053.      a1 += (d0>>2);
    2054.     do
    2055.     {
    2056.       d1 |= *a1++;
    2057.     } while (d7--);
    2058.        
    2059.      a1 = CollisionY;
    2060.      d0 = a2->SpriteMasterY.W.H;
    2061.      d0 += *a0++;
    2062.      d0 &= 0xfffc;
    2063.      d7 = *a0++;
    2064.      a1 += (d0>>2);
    2065.     do
    2066.     {
    2067.       d2 |= *a1++;
    2068.     } while (d7--);
    2069.        
    2070.     d1 &= d2;
    2071.  
    2072.      if ((d0=a2->SpriteCID) >= 0)
    2073.       d1 &= ~(1<<d0);      
    2074.    
    2075.     if (d1)
    2076.     {
    2077.         d7 = 31;
    2078.       do
    2079.       {
    2080.           if (d1 & (1<<d7))
    2081.         {
    2082.             a2->SpriteCResult |= CollisionIDList[d7]->SpriteClass;
    2083.         }
    2084.         } while (d7--);
    2085.     }
    2086.   }
    2087.  
    2088.   a2->SpriteCResult |= GlobalCollision;
    2089. }
    2090.  
    2091. /* ;-----------------------------------------------------------------------
    2092. ReadAllCollisions
    2093. ;                                                                              
    2094. ;                                                                              
    2095. ;----------------------------------------------------------------------   */        
    2096. void ReadAllCollisions(void)
    2097. {
    2098.   int i;
    2099.  
    2100.   for (i=0;i<16;i++)    /* for each plot priority (9 of 16 used!) */
    2101.   {
    2102.     a2=PlotPriority[i];
    2103.     while (a2)
    2104.     {
    2105.       ReadCollision();
    2106.       a2=a2->SpritePlotLink;  
    2107.     }
    2108.   }
    2109.  
    2110. }
    2111.                                                                                                                    
    2112.                                                                                                                    
    2113. /*---------------------------------------------------------------------------                                        
    2114. InitiateSprite                                                                                                        
    2115. ;                                                                                                                    
    2116. ; Initiate Sprite block, sets all defaults and necessary details first,                                              
    2117. ; then sets all specified fields                                                                                      
    2118. ; Requirements: PrimeData - PrimeList data address                                                                          
    2119. ;xx Returns     : pointer to data following prime data                                                                                                  
    2120. ; Returns     : pointer to new sprite (NULL if cannot initiate)
    2121. ;                                                                                                                    
    2122. ;---------------------------------------------------------------------------*/                                      
    2123. SPRITE *InitiateSprite(int ResSpriteNum)                                                                                        
    2124. {
    2125.   SPRITE *New;                                                                                                                    
    2126.   AMPDATA *Ret;
    2127.   AMPDATA *PrimeData;
    2128.  
    2129.   PrimeData = *(ResAMPs+ResSpriteNum);
    2130.  
    2131.                                  
    2132.   New = InactiveSprites;                                /* remember where one is */
    2133.   if (New != NULL)                                    /* if any available? */
    2134.   {                              
    2135.     InactiveSprites = InactiveSprites->SpriteLink;      /* unlink it */
    2136.                  
    2137.     memcpy(New,&SpriteReady,sizeof(SPRITE));            /* copy in defaults */
    2138.  
    2139.     New->SpriteLink = ActiveSprites;                    
    2140.     ActiveSprites = New;                              /* link into active list */
    2141.     ActiveSpriteCount++;
    2142.  
    2143.     Ret=InitiateBlock(New,PrimeData,sizeof(SPRITE));
    2144.  
    2145.     if (New->SpriteMPC == NULL)                        /* if MPC not set */
    2146.     {
    2147.       New->SpriteMPC = Ret;                           /* assume data follows */
    2148.     }
    2149.   }
    2150.  
    2151.   return(New);
    2152. }                                                                                                                    
    2153.                                                                                                                      
    2154. /*---------------------------------------------------------------------------                                          
    2155. InitiateBlock                                                                                                        
    2156. ;                                                                                                                    
    2157. ; Initialise Block with specific data.                                                                                  
    2158. ; Requirements: a0 - PrimeList data address                                                                          
    2159. ;      a1 - Target block                                                                                                
    2160. ;      a2 - Parent Block or NULL
    2161. ;      d0 - End of block offset for end condition                                                                    
    2162. ;      PrimeListEnd must match d0 passed                                                                              
    2163. ; Returns     : a0 - Next word after initiation block                                                                  
    2164. ;      a1 - Target block                                                                                                
    2165. ; Note: Optimised by Dominic!                                                                                          
    2166. ;                                                                                                                    
    2167. ;--------------------------------------------------------------------------- */
    2168. AMPDATA *InitiateBlock(SPRITE *New,AMPDATA *PrimeData,int Size)                                                                                
    2169. {                                                                                                                    
    2170.   AMPDATA Data;
    2171.   UBYTE *Target,*Source;
    2172.   UDWORD LDat;
    2173.  
    2174.   while (1)
    2175.   {
    2176.     Data = *PrimeData++;              /* read next field/offset */
    2177.     Target = (UBYTE *)(New);
    2178.     if (Data & 0x8000)
    2179.     {                                 /* 4 bytes of data (field/offset was inverted */
    2180.       Data = ~Data;
    2181.       Target += Data;
    2182.       LDat = *PrimeData++;
    2183.       LDat <<= 16;
    2184.       LDat += (UWORD)(*PrimeData++);
    2185.       *(UDWORD *)(Target) = LDat;   /* transfer 4 bytes from PrimeData */
    2186.     }
    2187.     else
    2188.     {
    2189.       if (Data == Size)               /* terminator = size of block */
    2190.         return(PrimeData);
    2191.       else if (Data > Size)               /* terminator > size of block */
    2192.         break;
    2193.  
    2194.       Target += Data;
    2195.       *(UWORD *)(Target) = *(UWORD *)(PrimeData);   /* transfer 2 bytes from PrimeData */
    2196.       PrimeData ++;
    2197.     }
    2198.   }
    2199.  
    2200.  
    2201. /* PUT INHERIT CODE HERE !!!! */
    2202.   while (1)
    2203.   {
    2204.     Data = *PrimeData++;              /* read next field/offset */
    2205.     Target = (UBYTE *)(New);
    2206.     Source = (UBYTE *)(a2);
    2207.     if (Data & 0x8000)
    2208.     {                                 /* 4 bytes of data (field/offset was inverted */
    2209.       Data = ~Data;
    2210.       Target += Data;
    2211.       Source += Data;
    2212.       LDat = *PrimeData++;
    2213.       LDat <<= 16;
    2214.       LDat += (UWORD)(*PrimeData++);
    2215.       *(UDWORD *)(Target) = LDat + *(UDWORD *)(Source);   /* transfer 4 bytes from Parent */
    2216.     }
    2217.     else
    2218.     {
    2219.       if (Data >= Size)               /* terminator > size of block */
    2220.         break;
    2221.  
    2222.       Target += Data;
    2223.       Source += Data;
    2224.       *(UWORD *)(Target) = (*PrimeData++) + *(UWORD *)(Source);   /* transfer 2 bytes from Parent */
    2225.     }
    2226.   }
    2227.  
    2228.  
    2229.  
    2230.  
    2231.   return(PrimeData);                                                                                                                                        
    2232. }                                    
    2233.                                    
    2234.                                    
    2235.                                    
    2236.                                    
    2237. /*                                                                               */
    2238. /*                                                                               */
    2239. /* ;--------------------------------------------------------------------------   */
    2240. /* ;                                                                              */
    2241. /* ; Alien Manoeuvre Program primitives.                                          */
    2242. /* ; Available :   a2 - Current sprite control block,                              */
    2243. /* ;      a3 - Current MPC, for relative jumps or accesses,                        */
    2244. /* ;      a5 - Global                                                               */
    2245. /* ;      d2 - Zero value at start of routine, see below,                           */
    2246. /* ;      d3 - Manoeuvre opcode word,                                             */
    2247. /* ;      d4 - First word parameter,                                                */
    2248. /* ;      d5 - Second word parameter,                                             */
    2249. /* ;      d6 - Third word parameter,                                                */
    2250. /* ; Returns   :   d2 - Return code word, 0=Ok                                    */
    2251. /* ;                    4=warning                                                   */
    2252. /* ;                    8=caution                                                   */
    2253. /* ;                    12=error                                                   */
    2254. /* ;                    16=disaster                                                */
    2255. /* ;      d3 - untouched                                                            */
    2256. /* ; Scratch   :   d0,d1,d7,a0,a1                                                   */
    2257. /* ;      d4-d6 and a3 may also be scratched                                       */
    2258. /* ;      d3 should not be corrupted                                                */
    2259. /* ; A non-zero return-code (d2) may cause an immediate jump to the MVector      */
    2260. /* ; if it is waiting for that value.                                             */
    2261. /* ;                                                                              */
    2262. /* ;---------------------------------------------------------------------------   */
    2263.  
    2264.  
    2265.  
    2266.  
    2267. /* ---------------------------------------------------------------------------
    2268. MLoop
    2269. --------------------------------------------------------------------------- */
    2270. void MLoop(void)
    2271. {
    2272.   AMPDATA *a0;
    2273.   AMPDATA d1;
    2274.   AMPDATA d4;
    2275.  
    2276.   d4= *ad;
    2277.  
    2278.    if (!(d4 & (1<<13)))
    2279.       {
    2280.       goto Fixed;
    2281.       }
    2282.    d4 &= 0x03ff;
    2283.    if (!d4)
    2284.       {
    2285.       goto Feedback;
    2286.       }
    2287.    d4 &= RandNum();
    2288. Fixed:
    2289.    if (!d4)
    2290.       goto Skip;
    2291.    a2->SpriteMLoop = d4;
    2292.    a2->SpriteMHead = a2->SpriteMPC;
    2293.    return;
    2294. Feedback:
    2295.    d4=Feedback;
    2296.    if (d4)
    2297.       goto Fixed;
    2298. Skip:
    2299.    a0 = a2->SpriteMPC; /* If Feedback = 0                        */
    2300. Loop:                 /* then search for                                       */
    2301.    while ((d1 = *a0++)>=0) ;     /* the EndLoop                        */
    2302.    
    2303.    d1 &= NotDelayFlag;
    2304.    if (d1 == (AMPDATA)((_EndLoop<<2)|Command))
    2305.       goto Found;
    2306.                      
    2307.    a0 += (d1 & 0x0003);    /* add length of amp parameters */
    2308.    goto Loop;
    2309. Found:
    2310.    a2->SpriteMPC = a0;
    2311. }
    It might be Graftgold's old ST code being ported to C, but I'm pretty sure it's not ST emulation.



    But what about Bubble Bobble? That's a bit harder to know for sure - I think the entire game lives in a file called "3.BIN" - everything else on the disc is either Rainbow Islands or the menus. What I do know is... it doesn't look like the ST port. But it's also not a perfect arcade conversion:



    The ST conversion is credited to Software Creations for Firebird - I don't think there's any relation at all other than "they're both ports of Bubble Bobble". But maybe Probe were developing a version of Bubble Bobble independently that got put on a shelf for a few years, idk. I suspect the Saturn version was ported from the PlayStation though don't quote me on that.

    tl;dr it's all a bit weird
     
    • Informative Informative x 1
    • List
  3. Bobblen

    Bobblen

    Member
    377
    192
    43
    Could be that they used the ST code as a reference for in-game logic rather than a direct port which wouldn't make alot of sense given how different the architectures are.
     
  4. Bo102010

    Bo102010

    Member
    55
    39
    18
    I added screenshots to Saturn Bomberman Fight!!/Hidden content. Here's a Mednafen cheat to unlock the bonus stages without needing a special controller:
    Code (Text):
    1. [18b088997c7ad5c514eab30b580971cf] Saturn Bomberman Fight!! (Japan)
    2. R A 1 B 0 0605dd90 01 BONUS_STAGES
    Don't have it enabled at bootup, or the Saturn BIOS won't load.
     
    • Informative Informative x 1
    • List
  5. Bobblen

    Bobblen

    Member
    377
    192
    43
    If you're still looking for cute mascot platformers to throw your disassembler at @Bo102010, here's a good mystery. Cheat sites list a whole bunch of codes for Rayman, but when we tested them all, we could only get one to work. Maybe it's another Croc where the Saturn has a cut down set of codes?

     
  6. Mentski

    Mentski

    Pff. Member
    221
    23
    18
    Parts Unknown
    Being a mysterious face.
    It's possible... From what I recall, accurate emulation of the arcade game wasn't even possible until the protection MCU was decapped some time in the mid-2000s, due to the game logic running directly through it.

    Prior to that, Emulated Bubble Bobble played wrong... Yeah, I know, we're talking ports here rather than emulation, but the fact that game behaviour back then would've been entirely down to eyeballing rather than reverse-engineering, maybe they went back to the work of a team that had already done the lion's share.

    *does quick google search* - Here we go:

    When it comes to Graftgold's ports of Rainbow Islands, Taito gave them every piece of material they ever needed for a 1:1 recreation when they were making the ST/Amiga ports. There were articles in magazines at the time, about the unprecedented partnership between Taito and Ocean that had never really happened with licensees in the past, where they were giving them design docs and original graphics discs. A lot of Ocean's later Taito ports are *very* accurate to the originals because of this.
     
    Last edited: Jan 16, 2024
    • Informative Informative x 1
    • List
  7. Bobblen

    Bobblen

    Member
    377
    192
    43
    According to this, Taito gave them the graphics and design docs but not the source code! Their versions have the secret islands because one of the devs was good enough at the arcade game to actually unlock them (and the mapping was done by watching video of the guy playing and pausing it to sketch the maps). I love the UK 8 bit Micro scene, it was just the wild west, you can't imagine it these days. They did a hell of a job given those circumstances!

    Rainbow Islands | The Beginning (uridiumauthor.blogspot.com)

    EDIT - I misread and got it backwards, the 8 bit versions don't have the secret islands, they were only discovered by playing the arcade game during development and they weren't able to get them in!
     
    Last edited: Jan 16, 2024
    • Informative Informative x 1
    • List
  8. Rlan

    Rlan

    Oldbie
    290
    293
    63
    While you're on a cheat code hunt, it might be good for you to go through this: Getting Bean in Virtua Striker games.

    https://forums.sonicretro.org/index.php?threads/bean-the-dynamite-in-virtua-striker-2.36524/

    There's an idea of what you actually need (50 wins), but might be good to check Arcade, Dreamcast etc versions and see if Bean still exists in them all. It'd also be great if you can find any way to hack a save file so this can occur without people having to wing 50 damn games as one team :P
     
  9. Bobblen

    Bobblen

    Member
    377
    192
    43
    Interesting, an easter egg cameo appearance that only triggers after the machine has been used for a long while isn't unheard of. As you say though, it'd have to be a hack, no one in their right mind is winning 50 games in a row for real. Super model is now a really solid emulator, which makes it a bit more plausible to investigate.

    Here's a cheat table for 'always 99 goals' for someone to grind through if they particularly want to (untested)
    Supermodel Forum • View topic - Model 3 cheat database! (supermodel3.com)

    EDIT - ended up doing it myself in cheat engine rather than artmoney which I've never used before. I'll leave it to win a bunch of 1 minute game tournaments for a bit and see what happens :-)

    EDIT 2 - should have seen this coming, when you win a tournament it's supposed to do a bunch of replays of the 'winning goal' of each match over the credits. Except I have no winning goal so it crashes :-D. Oh well.
     
    Last edited: Jan 17, 2024
  10. Black Squirrel

    Black Squirrel

    no reverse gear Wiki Sysop
    8,606
    2,483
    93
    Northumberland, UK
    steamboat wiki
    If we're tackling Model 3 mysteries that one would be nice.

    Virtua Striker 2 is annoying because there are a bazillion revisions:
    Virtua Striker 2
    Virtua Striker 2 Version '98
    Virtua Striker 2 Version '99
    Virtua Striker 2 Ver. 2000
    Virtua Striker 2 Ver. 2000.1
    and there are genuine differences between them all. So if it's a case of having them all win 50 games then managing to get one of the secret teams to make a substitution... yeah.

    This is one where you really need to hack the game - if Bean is a subtitute... well teams usually have more than one sub. Ideally we'd want to have a list (and screenshots?) of the full team... which tbh we'd need anyway even if they weren't fun secret characters.

    Case in point: FC Sega is made up of Sega developers. So there could be real people in there that you essentially never see. And then we have the revisions that remove and/or replace teams - do these older teams still exist?


    Mind you, could be worse. Fighters Megamix infamously unlocks the AM2 palm tree after 84 hours of play* - were this an arcade game, it's not inconceivable that a new player would arrive on a machine that had already exceeded this play time. Thus the palm tree wouldn't be "hidden" (and at popular venues, it might be rare to see the game in a pre-84 hour state).


    *fun fact: I never confirmed this. Because even with emulation, simulating 84 hours is... unpleasant.
     
    • Informative Informative x 1
    • List
  11. Bobblen

    Bobblen

    Member
    377
    192
    43
    Indeed, I was gonna try it once on vf2 (and even that is US step 2, there's a Japan step 1.5 which might be a better choice) and be done with it! But the crash thing makes it a pain to automate so probably not. I'll leave it to future reverse engineers instead.
     
  12. Bo102010

    Bo102010

    Member
    55
    39
    18
    Hoo boy, this was a rabbit hole. The button handling code in Rayman is actually insane. Most games store button presses in a 16-bit field of flags have something like a buffer of recent inputs that they compare to a list of valid bit patterns.

    Rayman uses a 16-bit field of flags for button presses, but it turns around and maps each button's pattern to a numerical value: 00 is up, 01 is down, etc. Then it uses the mapping for your first button press to decide which code to track, and from there says how many buttons need to be held for each part of the code. I'll write up the technical details eventually...

    Anyway, here is the set of codes that do something legible:
    • 5 lives: B, X, B, Z, LT+RT+Down+B
    • 99 Lives: Up, X+B+Z, LT, RT, LT, RT, Up+Y
    • 10 continues: Left, A+C, RT+LT+Z, X+Z+Up
    • 20 lives: A, Right+B, Down+Left+RT, Y+C+Z
    • Full health: RT, Down, Left, Up, Right, B+C, LT+RT
    You have to put the multi-button ones in as shown. Like you have to hold LT, then RT, then Down, then B.

    There are three others that the game recognizes:
    • Unknown 1: LT, X, A, X, LT, Down
    • Unknown 2: Right, A+Z+X, Y+B+RT, LT+X+C, Left+A+B+C, Right
    • Unknown 3: C, Right+A, Z+Left+C, X
    I don't know what they do! Are there any Rayman experts who can try them and see? My actual guess is that they don't do anything.

    You can set a break point for 0601304e to see if you've entered them correctly, since you may not be able to tell otherwise.
     
    • Like Like x 2
    • Informative Informative x 1
    • List
  13. Bobblen

    Bobblen

    Member
    377
    192
    43
    Crikey, that's lightning fast work, well done! Pinging @BSonirachi and @Chimes who expressed interest in this back in 2022(!). This is basically new knowledge, although there's stuff like this list, where the codes sort of resemble the 5 understood correct ones (and have the correct descriptions) but there's mistakes in all of them which explains why they never worked for anyone.
    Rayman Cheats, codes, hints, tips, tricks (Sega Saturn) (consoledatabase.com)

    Does anyone know whether there's a Rayman discord or fansite or something we can toss these over to? Bet unknown 2 does something cool will all those buttons.
     
  14. Chimes

    Chimes

    The One SSG-EG Maniac Member
    625
    482
    63
    @RibShark yo peep this one
    There indeed is. There's the RayWiki and the Rayman Pirate Community, and both of them have discords. I'll hand some of the info to the RPC
     
    Last edited: Jan 17, 2024
  15. Black Squirrel

    Black Squirrel

    no reverse gear Wiki Sysop
    8,606
    2,483
    93
    Northumberland, UK
    steamboat wiki
    Actually did some proper digging. He's not.

    Amiga/ST Bubble Bobble was programmed by David Broadhurst, who just so happened to also work on the Saturn/PS1 versions.
    https://www.lemonamiga.com/interviews/david_broadhurst/
    According to this interview, the Amiga/ST version was made by eyeing up an arcade cabinet, whereas Taito provided some actual documentation for the Saturn/PS1 versions.

    So I guess any quirks in the Saturn version should be entirely separate to the older computer ports.
     
    • Informative Informative x 1
    • List
  16. Bobblen

    Bobblen

    Member
    377
    192
    43
    A real 8-bit home computers dream team, Bubble Bobble by Software Creations and Rainbow Islands by Graftgold. Neat.
     
  17. Bobblen

    Bobblen

    Member
    377
    192
    43
    Some good Rayman stuff in @Bo102010 's twitter at the moment, the three unknown codes appear to be disabled but had functionality in a prototype. The proto even came with a paper guide to the codes (which have different button combos compared to release). I'll hold fire on adding to the wiki until it all shakes out!
    Bo (Low Context Burning Rangers) on X
     
    • Informative Informative x 1
    • List
  18. Black Squirrel

    Black Squirrel

    no reverse gear Wiki Sysop
    8,606
    2,483
    93
    Northumberland, UK
    steamboat wiki
    [​IMG]
    Ah, um, yes, okay.

    Rayman (prototype; 1995-07-20) was dumped back in 2015 and actually came with a piece of paper with codes on it. And that image is included in the RAR mirrored on Hidden Palace. Oop.

    I'm surprised this hasn't been covered in more obvious detail. Granted it's a port of an then-already finished Jaguar game, but the series is pretty popular online, and all the versions of Rayman differ slightly.
     
    • Informative Informative x 1
    • List
  19. Black Squirrel

    Black Squirrel

    no reverse gear Wiki Sysop
    8,606
    2,483
    93
    Northumberland, UK
    steamboat wiki
    Ooooh ooh I understand now - it's because the details aren't obvious.

    I spent about five minutes with the prototype - there's a lot of differences in the initial presentation, but when you get into game... it's incredibly similar to the final. Which in turn will be incredibly similar to the Jaguar version.

    And while I appreciate Rayman 1, I've always found it a bit of a "slow" game compared to... well pretty much any Rayman release since. I'm not sure I want to be sitting down with all the different versions to see how close this Saturn prototype is to any of them, especially if the bigger differences turn out to be in the latter half.

    One point of note though: this prototype is missing the initial FMV when you start a game. It's instead a slideshow... with a Japanese voiceover. It may be worth checking, if you haven't already, that the GameFAQs codes don't work in the final Japanese version, if it turns out that one was finished first.
     
  20. Bo102010

    Bo102010

    Member
    55
    39
    18
    I confirmed a few things by comparing the prototype code to to the final version code:
    • The functions that implement the cheats appear in the same order in both versions
    • The three extra ones in the prototype correspond to the three that jump to the same place in the final
    • The button presses are easier to execute in the prototype because they're all single-button, and correspondingly, the code in the prototype is much simpler
    • The functions to implement the missing three codes in the final are just totally gone; they're not present-but-unused
    In any case, we know some new AR codes for Rayman now.