Advertisement
Bisqwit

Castlevania II insertor: Status screen patch generator

Mar 12th, 2013
576
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 15.52 KB | None | 0 0
  1. <?php
  2.  
  3. /* From NES Castlevania II - Simon's Quest ROM hacking project */
  4. /* Copyright (C) Joel Yliluoma - http://iki.fi/bisqwit/cv2fin/ */
  5.  
  6. function ChangeDialogBoxShape()
  7. {
  8.   global $linker, $space, $PAL, $settings;
  9.  
  10.   $timer_oneliner = true;
  11.  
  12.   $decreased_margin = 1;
  13.   $added_lines = 2; // How many lines were added into the shopping text?
  14.   $added_width = 0;
  15.  
  16.   $tight_lines = true;
  17.  
  18.   $plans = Array(
  19.    'status' => $settings['SUPPORT_MULTICLUE']
  20.                      ? ($timer_oneliner
  21.                         ? 'top/time0/0/LBL1/heart/mid/0/mid/0/0/mid/0/0/0/0/mid/LBL2/bot'
  22.                         : 'top/LBL0/time/LBL1/heart/mid/0/mid/0/0/mid/0/0/0/0/mid/LBL2/bot')
  23.                        
  24.                      : 'top/LBL0/time/0/LBL1/0/heart/mid/0/mid/0/0/mid/0/0/0/0/bot',
  25.    'shop'   => 'top1/1/1/1/1/1/1/1/cost/1/1/yes/no/bot1',
  26.    'dfl'    => 'top1/1/1/1/1/1/1/1/1/1/1/bot1'
  27.   );
  28.  
  29.   $graphs = LoadTextConfig($settings['DIALOGBOX_FILE']);
  30.  
  31.   $allowed_banks = Array(0x1C000);
  32.   if($settings['MOVE_DIALOGBOX_TO_BANK3'])
  33.   {
  34.     $allowed_banks = Array(0xC000);
  35.   }
  36.  
  37.   foreach($plans as $planname => $plan)
  38.   {
  39.     $b = new Blob("DialogBoxTable_$planname");
  40.     foreach(explode('/', $plan) as $piecename)
  41.       $b->AppendPointerto("DialogBoxGraph_$piecename");
  42.     $linker->AddBlob($b, $allowed_banks); // Put somewhere in this page.
  43.   }
  44.   foreach($graphs as $piecename => $graph)
  45.   {
  46.     $b = new Blob("DialogBoxGraph_$piecename",
  47.       EncodeGfxRender(EncodeDialog($graph,false)));
  48.     $linker->AddBlob($b, $allowed_banks); // Put somewhere in this page.
  49.   }
  50.  
  51.   $b = new Blob("DialogBoxTable_LengthsMinus1");
  52.   for($round=0; $round<2; ++$round)
  53.     foreach(explode('/', 'status/dfl/shop/dfl/dfl/dfl/dfl/dfl') as $planname)
  54.     {
  55.       $length = count(explode('/', $plans[$planname]));
  56.      
  57.       if($round == 0) $b->AppendRawData(chr($length - 1));
  58.       else            $b->AppendPointerTo("DialogBoxTable_$planname");
  59.     }
  60.   $b->AddPublicAt("DialogBoxTable",   $b->GetSize() / 3);
  61.   $b->AddPublicAt("DialogBoxTableHi", $b->GetSize() / 3 + 1);
  62.  
  63.   #$p = 0;
  64.  #if($PAL) $p -= 77;
  65.  
  66.   $location = $PAL ? 0x1F5E4 : 0x1F631;
  67.   if($settings['MOVE_DIALOGBOX_TO_BANK3'])
  68.   {
  69.     $linker->AddBlob($b, $allowed_banks);
  70.     $space[$location] = 0x1F708-0x1F631; // Relieve the space that used to store this data.
  71.  
  72.     $b = new Blob("DialogBox_ReferToLengthTable");
  73.     $b->AppendPointerTo("DialogBoxTable_LengthsMinus1");
  74.     $linker->AddBlob($b, $PAL ? 0x1EFDB-77 : 0x1EFDB, true);
  75.  
  76.     $b = new Blob("DialogBox_ReferToDialogBoxTable");
  77.     $b->AppendPointerTo("DialogBoxTable");
  78.     $linker->AddBlob($b, $PAL ? 0x1F585-77 : 0x1F585, true);
  79.  
  80.     $b = new Blob("DialogBox_ReferToDialogBoxTableHi");
  81.     $b->AppendPointerTo("DialogBoxTableHi");
  82.     $linker->AddBlob($b, $PAL ? 0x1F58A-77 : 0x1F58A, true);
  83.  
  84.     // Jumped to from 1D349
  85.     $b = new Blob("Jump_To_ItemMenuPauseScreen_Run",
  86.       // jsr $D4E6 -- which has code that does lda #3,jsr SwitchBank_NewPage,rts
  87.       // Jmp ItemMenuPauseScreen_Run
  88.       $PAL ? "\x20\x99\xD4\x4C\x06\xEF"
  89.            : "\x20\xE6\xD4\x4C\x53\xEF"
  90.     );
  91.     $linker->AddBlob($b, 0x1C000);
  92.    
  93.     $b = new Blob("Jump_To_ItemMenuPauseScreen_Run2");
  94.     $b->AppendJumpPointerTo("Jump_To_ItemMenuPauseScreen_Run");
  95.     $linker->AddBlob($b, $PAL ? 0x1D349-77 : 0x1D349, true);
  96.   }
  97.   else
  98.   {
  99.     $linker->AddBlob($b,  $location, true); // Fixed location for these pointers + length table
  100.     $space[$location+8*3] = 0x1F708-0x1F649; // Relieve the space that used to store this data.
  101.   }
  102.  
  103.   $b = new Blob("MerchantDealLine",  chr(6+$added_lines)); // Set Y coordinate for deal listing
  104.   $linker->AddBlob($b, $PAL?0x1EC7E:0x1ECCB, true);
  105.   $b = new Blob("MerchantDealItemX", chr(2)); // Set x coordinate for item symbol
  106.   $linker->AddBlob($b, $PAL?0x1EC8C:0x1ECD9, true);
  107.   $b = new Blob("MerchantDealCostX", chr(7)); // Set x coordinate for heart count
  108.   $linker->AddBlob($b, $PAL?0x1ECA1:0x1ECEE, true);
  109.  
  110.   $b = new Blob("MerchantCursorPatch1", chr(8+$added_lines)); // Set Y coordinate for merchant cursor moving
  111.   $linker->AddBlob($b, $PAL?0x1ED0F:0x1ED5C, true);
  112.   $b = new Blob("MerchantCursorPatch2", chr(8+$added_lines)); // Set Y coordinate for merchant cursor blinking
  113.   $linker->AddBlob($b, $PAL?0x1EDE5:0x1EE32, true);
  114.   $b = new Blob("MerchantCursorPatch3", chr(2-$decreased_margin)); // Set Y coordinate for first text line
  115.   $linker->AddBlob($b, $PAL?0x1EE08:0x1EE55, true);
  116.  
  117.   $b = new Blob("StatusBoxLengthPatch1", chr( count(explode('/', $plans['status'])) ));
  118.   $linker->AddBlob($b, $PAL?0x1EF81:0x1EFCE, true);
  119.  
  120.   $b = new Blob("StatusBoxLengthPatch2", chr( count(explode('/', $plans['status'])) ));
  121.   $linker->AddBlob($b, $PAL?0x1F3A3:0x1F3F0, true);
  122.  
  123.   // Repositioning the merchant cursor horizontally:
  124.   $b = new Blob("MerchantCursorXpatch4", chr(0x17).chr(0x03));
  125.   $linker->AddBlob($b, $PAL ? 0x1EDC3 : 0x1EE10, true);
  126.  
  127.   // A wider dialog box requires wider attribute patch.
  128.   #$b = new Blob("test", chr(8 + ($added_width/2)));
  129.  #$linker->AddBlob($b, 0x1F715, true);
  130.  
  131.   if($added_width > 0)
  132.   {
  133.     $b = new Blob("AssignDialogAttributeWidth", "\xEA");
  134.     $b->AppendCallPointerTo("DetermineDialogAttributeWidth");
  135.     $linker->AddBlob($b, $PAL ? 0x1F6C7 : 0x1F714, true);
  136.    
  137.     /*   ldy #8
  138.      *   lda DialogText_Saved_CharacterIndex ($7E)
  139.      *   beq +
  140.      *   ldy #8 + $added_width
  141.      *   sty $17 (from 1F716)
  142.      * + rts
  143.      */
  144.     $b = new Blob("DetermineDialogAttributeWidth",
  145.       "\xA0\x08".
  146.       "\xA5\x7E".
  147.       "\xF0\x02".
  148.       "\xA0".chr(8 + ($added_width/2)).
  149.       "\x84\x17".
  150.       "\x60"
  151.       );
  152.     $linker->AddBlob($b, 0x1C000); // anywhere in common bank
  153.   }
  154.  
  155.   // The following patch causes visual artifacts during dialog rendering,
  156.   // but it allows for larger boxes.
  157.   if($added_width > 0)
  158.   {
  159.     $b = new Blob("ConditionalRemoveDialogBoxLineParityForce", "\xEA");
  160.     $b->AppendCallPointerTo("TestIfDialogBoxIsFast");
  161.     $linker->AddBlob($b, $PAL ? 0x1F44B : 0x1F607, true);
  162.     /*
  163.        lda DialogText_Saved_CharacterIndex ($7E)
  164.        bne +
  165.        ; reached only if $7E=0.
  166.        lda DialogText_Saved_ID ($79)
  167.        and #$01
  168.        rts
  169.      + lda #0  ;return Z
  170.        rts
  171.     */
  172.     $b = new Blob("TestIfDialogBoxIsFast", // nonzero (NE) = render another immediately
  173.       "\xA5\x7E".
  174.       "\xD0\x05".
  175.       "\xA5\x79".
  176.       "\x29\x01".
  177.       "\x60".
  178.       "\xA9\x00\x60" // lda #0; rts
  179.     );
  180.     $linker->AddBlob($b, 0x1C000); // anywhere in common bank
  181.   }
  182.  
  183.   /* The following patch ensures that if the dialog box includes
  184.      the character [48], or [1C], it is rendered at maximum speed
  185.      and not beeped over.
  186.      Additionally, some punctuation is made to pause slightly longer.
  187.      It also enables dialog text table being 256 elements long
  188.      rather than just 128.
  189.      dialog_fast.s also includes code for turbo-rendering text
  190.      when A button is held.
  191.   */
  192.   $location = $PAL ? 0x1EE57 : 0x1EEA4;
  193.  
  194.   $asm_name = sprintf('dialog_fast_%s.bin',
  195.     $PAL?'pal':'ntsc');
  196.   $b = LoadAsmBlob("DialogAction_RenderMessage_WithDelayCheck", $asm_name);
  197.   $linker->AddBlob($b, 0xC000); // anywhere in bank 3
  198.   $space[$location] = (0xEF0A-0xEEA4); // Relieve the code that was replaced
  199.  
  200.   // Patch up references to this code
  201.   foreach(Array(0x1EBBC,0x1EBD1,0x1EBE6,0x1EC18,0x1EC49,0x1EC62) as $location)
  202.   {
  203.     $b = new Blob(sprintf("Refer_DialogAction_RenderMessage_%X", $location), "");
  204.     $b->AppendPointerTo("DialogAction_RenderMessage_WithDelayCheck");
  205.  
  206.     $linker->AddBlob($b, $location + ($PAL?-77:0), true);
  207.   }
  208.  
  209.  
  210.   /*
  211.     Delete Rosary rendering from whip-line:
  212.       F194 lda #$0E
  213.            jsr $F1BD ; move forward
  214.            lda $92   ; items1
  215.            and #$01
  216.            beq + (+8)
  217.            jsr $E394 ; put3bytes
  218.            lda #$5C
  219.            jsr $EB9C ;putAandFF
  220.          + rts;jmp $F0FC ;godowntwolines
  221.       Free until F1BD
  222.   */
  223.   $location = $PAL?0x1F147:0x1F194;
  224.   $space[$location] = 0xF1BD-0xF194;
  225.   $b = new Blob("StatusBox_MoveRosary_Part1",
  226.     "\xA9\x0E".
  227.     ($PAL?"\x20\x70\xF1":"\x20\xBD\xF1").
  228.     "\xA5\x92\x29\x01\xF0\x08".
  229.     ($PAL?"\x20\x47\xE3":"\x20\x94\xE3").
  230.     "\xA9\x5C".
  231.     ($PAL?"\x4C\x4F\xEB":"\x4C\x9C\xEB").
  232.     "\x60");
  233.   $linker->AddBlob($b, $location, true);
  234.   $linker->RemoveSpace($space, $location, $b->GetSize());
  235.  
  236.   /*
  237.     Add Rosary rendering to the bodyparts line:
  238.     F030 jmp RosaryRender
  239.     RosaryRender:
  240.       lda $92
  241.       and #$02
  242.       beq +
  243.       jsr $E394
  244.       lda #$5A
  245.       jsr $EB9C
  246.     + rts;jmp $F0FC
  247.   */
  248.  
  249.   $b = new Blob("StatusBox_MoveRosary_Part2");
  250.   $b->AppendJumpPointerTo("RosaryRender");
  251.   $linker->AddBlob($b, $PAL?0x1EFE3:0x1F030, true);
  252.  
  253.   $b = new Blob("RosaryRender",
  254.     "\xA9\x02".
  255.     ($PAL?"\x20\x70\xF1":"\x20\xBD\xF1").
  256.     "\xA5\x92\x29\x02\xF0\x08".
  257.     ($PAL?"\x20\x47\xE3":"\x20\x94\xE3").
  258.     "\xA9\x5A".
  259.     ($PAL?"\x4C\x4F\xEB":"\x4C\x9C\xEB").
  260.     "\x60");
  261.   $linker->AddBlob($b, 0xC000); // anywhere in page 3
  262.  
  263.   /* Enable Rosary selection:
  264.    *
  265.    *  F289 jmp EnableRosarySelection
  266.    * EnableRosarySelection:
  267.    *   sta $93
  268.    *   lda $92
  269.    *   and #$02
  270.    *   beq +
  271.    *   lda #$40
  272.    *   ora $93
  273.    *   sta $93
  274.    * + lda $93
  275.    *   jmp $1F2D2
  276.    */
  277.   $b = new Blob("StatusBox_EnableRosarySelect");
  278.   $b->AppendJumpPointerTo("RosarySelectEnabler");
  279.   $linker->AddBlob($b, $PAL?0x1F23C:0x1F289, true);
  280.  
  281.   $b = new Blob("RosarySelectEnabler",
  282.     "\x85\x93\xA5\x92\x29\x02\xF0\x06".
  283.     "\xA9\x40\x05\x93\x85\x93\xA5\x93".
  284.     ($PAL?"\x4C\x85\xF2":"\x4C\xD2\xF2"));
  285.   $linker->AddBlob($b, 0xC000); // anywhere in page 3
  286.  
  287.   // Rosary is now a new selectable item in the bodyparts line, so change some limits.
  288.   $b = new Blob("BodyPartMin", "\x07");
  289.   $linker->AddBlob($b, $PAL?0x1F21F:0x1F26C, true);
  290.   $b = new Blob("BodyPartMax", "\x08");
  291.   $linker->AddBlob($b, $PAL?0x1F278:0x1F2C5, true);
  292.  
  293.   // Rewrite GoDownTwoLines so that we can extract "GoDownOneLine" from it
  294.   $b = new Blob("DialogBox_GoDownTwoLines", "\xE6\x77\xE6\x79" . "\xE6\x77\xE6\x79" . "\x60");
  295.   $b->AddPublicAt("DialogBox_GoDownOneLine", 4);
  296.   $linker->AddBlob($b, 0x1F0FC-($PAL?77:0), true);
  297.  
  298.   // Utility function for going just one line down.
  299.   $b = new Blob("DialogBox_Go1Down_And_Recalculate");
  300.   $b->AppendCallPointerTo("DialogBox_GoDownOneLine");
  301.   $b->AppendRawData(($PAL ? "\x20\x1C\xEE" : "\x20\x69\xEE")."\xA5\x5E\x29\x20\x85\x16\x60");
  302.   $b->AddPublicAt("Odd_5E16flip", $b->GetSize()-7);
  303.   $linker->AddBlob($b, 0x1C000); // anywhere in common page
  304.  
  305.   // Declare the locations of these functions, so we can nicely call them by name.
  306.   $linker->AddBlob(new Blob("DialogBox_RenderTwoDigitNumber"),  $PAL ? 0x1F17F : 0x1F1CC, true);
  307.   $linker->AddBlob(new Blob("DialogBox_GoForwardHorizontally"), $PAL ? 0x1F170 : 0x1F1BD, true);
  308.  
  309.   // Original layout of status screen numeric elements.
  310.   $renderers = Array
  311.   (
  312.     //name         Yoffs Xoffset  Variable=>Xincrement
  313.     'time'   => Array(2, 6, Array(0x83=>0, 0x86=>3, 0x85=>3)),
  314.     'exp'    => Array(4, 4, Array(0x47=>0, 0x46=>2)),
  315.     'level'  => Array(4, 12,Array(0x8B=>0)),
  316.     'hearts' => Array(6, 4, Array(0x49=>0, 0x48=>2)),
  317.     'whip'   => Array(8, 2, Array( 0xF163 - ($PAL?77:0) => 0)  ),
  318.     'body'   => Array(11,0, Array( 0xEFF4 - ($PAL?77:0) => 0)  ),
  319.     'items'  => Array(14,0, Array( 0xF042 - ($PAL?77:0) => 0)  ), // aka. weapons
  320.     'herbs'  => Array(16,2, Array( 0xF06E - ($PAL?77:0) => 0)  )
  321.   );
  322.   $space[0x1EFEB-($PAL?77:0)] = 9; // the beginning of RenderBodyParts
  323.   $space[0x1F069-($PAL?77:0)] = 5; // the beginning of RenderLaurelsAndGarlics
  324.   $space[0x1F105-($PAL?77:0)] = 0xF15E-0xF105; // Renderers for Time, Exp, Level, Hearts.
  325.   // Don't delete the beginning of RenderWhipName, because it is used by whip_ext.s .
  326.  
  327.   // Change whip, body, items, herbs renderers to NOT call DialogBox_GoDownTwoLines at the end
  328.   foreach(Array(/*0x1F030,*/0x1F066,0x1F0C1/*,0x1F1BA*/) as $location)
  329.   {
  330.     if($PAL) $location -= 77;
  331.     $b = new Blob(sprintf("Patch_%X", $location), "\x60");
  332.     $linker->AddBlob($b, $location, true);
  333.     $space[$location+1] = 2;
  334.   }
  335.  
  336.   // Rightalign the Exp. value (experience or E-points)
  337.   $renderers['exp'][1] = 10;
  338.   // Move level (L) to the same row as the hearts. Keep it right-aligned.
  339.   $renderers['level'][0] = 6;
  340.  
  341.   if($settings['SUPPORT_MULTICLUE'])
  342.   {
  343.     // Condense by two lines.
  344.     $renderers['exp'][0]    -= 1;
  345.     $renderers['hearts'][0] -= 2;
  346.     $renderers['level'][0]  -= 2;
  347.     $renderers['whip'][0]   -= 2;
  348.     $renderers['body'][0]   -= 2;
  349.     $renderers['items'][0]  -= 2;
  350.     $renderers['herbs'][0]  -= 2;
  351.    
  352.     $renderers['clues'] = Array(16,12, Array("DialogBox_RenderClues" => 0));
  353.  
  354.     // Experimental: Move the clock to the first line.
  355.     $renderers['time'][0]   -= 1;
  356.     $renderers['time'][1]   -= 1; // Move 1 character to the left, as well
  357.   }
  358.  
  359.   // For each pair of two lines, list what goes on that linepair.
  360.   $renderers_per_linepair = Array();
  361.   foreach($renderers as $name => $configuration)
  362.   {
  363.     $line   = $configuration[0];
  364.     $column = $configuration[1];
  365.     $script = $configuration[2];
  366.     $renderers_per_linepair[ $line &~ 1 ] [ ($line&1) ] [$column] = $script;
  367.   }
  368.  
  369.   // Generate the renderers for each of these line pairs.
  370.   foreach($renderers_per_linepair as $y2 => $lines)
  371.   {
  372.     ksort($lines);
  373.  
  374.     $b = new Blob( sprintf("DialogBox_Render_LinePair%d", $y2) );
  375.     $prevline = 0;
  376.     foreach($lines as $line => $columns)
  377.     {
  378.       for(; $line > $prevline; ++$prevline)
  379.         $b->AppendCallPointerTo("DialogBox_Go1Down_And_Recalculate");
  380.      
  381.       $prevcolumn = 0;
  382.       ksort($columns);
  383.      
  384.       foreach($columns as $column => $script)
  385.         foreach($script as $item => $increment)
  386.         {
  387.           $column += $increment;
  388.           if($column > $prevcolumn)
  389.           {
  390.             $b->AppendRawData("\xA9" . chr($column - $prevcolumn)); // LDA #imm
  391.             $b->AppendCallPointerTo("DialogBox_GoForwardHorizontally");
  392.             $prevcolumn = $column;
  393.           }
  394.           if(is_string($item))
  395.             $b->AppendCallPointerTo($item);
  396.           elseif($item >= 0x1000)
  397.           {
  398.             $b->AppendRawData("\x20" . chr($item & 0xFF) . chr($item >> 8)); // JSR
  399.           }
  400.           else
  401.           {
  402.             $b->AppendRawData("\xA5" . chr($item & 0xFF)); // LDA zp
  403.             $b->AppendCallPointerTo("DialogBox_RenderTwoDigitNumber");
  404.             $prevcolumn += 1;
  405.           }
  406.         }
  407.     }
  408.     if($prevline == 0)     $b->AppendJumpPointerTo("DialogBox_GoDownTwoLines");
  409.     elseif($prevline == 1) $b->AppendJumpPointerTo("DialogBox_GoDownOneLine");
  410.     else $b->AppendRawData("\x60");
  411.  
  412.     $linker->AddBlob($b, 0xC000); // anywhere in page 3
  413.   }
  414.  
  415.   $location = 0x1F0CF-($PAL?77:0);
  416.   $space[$location] = 0xF0FC-0xF0CF;
  417.   $b = new Blob("DialogBox_RenderStatusBoxLine_tail");
  418.   $b->AppendCallPointerTo("Odd_5E16flip");
  419.   $b->AppendRawData("\xA5\x79"); // lda linenumber
  420.   $b->AppendJumpPointerTo("DialogBox_RenderStatusBoxLine_Generated");
  421.   $linker->AddBlob($b, $location, true);
  422.   $linker->RemoveSpace($space, $location, $b->GetSize());
  423.  
  424.   $b = new Blob("DialogBox_RenderStatusBoxLine_Generated");
  425.   foreach($renderers_per_linepair as $y2 => $lines)
  426.   {
  427.     $b->AppendRawData("\xC9" . chr($y2) ); // cmp #imm
  428.     $b->AppendRawData("\xD0\x03"); // bne +
  429.     $b->AppendJumpPointerTo( sprintf("DialogBox_Render_LinePair%d", $y2) );
  430.   }
  431.   $b->AppendJumpPointerTo("DialogBox_GoDownTwoLines");
  432.   $linker->AddBlob($b, 0xC000); // anywhere in page 3
  433. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement