Jimmie1717 icon

BizHawk: Jet Force Genocide Script

Jimmie1717 | PRO | 06/17/16 10:22:14 PM UTC | 0 ⭐ | 1580 👁️ | Never ⏰ | []
Lua |

17.39 KB

|

None

|

0 👍

/

0 👎

-- Jet Force Genocide Script
-- This script will only work for the English and Japanese Versions.
 
-- What is Jet Force Genocide? -------------------------------------------------------------
-- This is a hack that reverses how Tribals work. When a Tribal is 'saved' it is counted as
-- 'killed' and vice versa. This means that in order to be able to beat the game the player
-- must go through the game and kill all the Tribals instead of saving them. Reversing how
-- they work is necessary to make the game beatable. This is because as far as the game is
-- concerned all the Tribals must be saved to do so.
 
-- Emulator: -------------------------------------------------------------------------------
-- Use BizHawk 1.11.6 (or higher)
-- After loading the ROM use N64 -> Plugins
-- For Global Plugin Settings use:
--      Core Type:              DynaRec
--      Rsp Plugin:             Hle
--      Active Video Plugin:    Jabo 1.6.1
--      Video Resolution:       640x480 (text display is setup for this resolution)
-- It seems if the core type is set to interperter (pure or not) the Lurg Fight can crash the game.
-- Jabo Video plugin is the best as it shows the manual targetting reticles while the others don't.
-- However there are a few errors with it on the Japanese Version.
-- The Lurg Boss Fight and Chasm Night Vision Sections are covered by a black screen.
-- This prevents you from being able to see. So I disabled them.
-- These errors don't seem to happen on the English version but I still disabled to make sure it works.
 
-- How to use this:
-- On pastebin.com click the download button on the upper right side of the code frame to download this file as a .lua file.
-- In BizHawk open the Lua Console. (Tools -> Lua Console)
-- In Lua Console open the .lua file. (Script -> Open Script -> <browse to file>)
 
-- NOTES: ----------------------------------------------------------------------------------
-- I added an check for invalid tribal counts.
-- A message will pop up in the bottle left of the BizHawk window if it happens.
-- If this happens the saved and killed counts will reset to 0.
-- This could cause an issue with remaining tribals though if it happens in the middle of a region.
-- If it happens at the very beggining of the region it should be fine.
-- This error shouldn't happen anymore, but I put this in just in case.
 
-- I also added a Tribal Count Display (above the weapon hud).
-- The format for it is as follows: <saved> <killed> <remaining> <total kill count>
-- This will make it easy to tell if the counts are off some how.
-- The display is setup for 480p.
 
-- Levitation is enabled since as a tribal you can't use the Jet Pack.
-- However it is still based on Jet Fuel. You need to have Jet Fuel to be able to levitate.
-- It works the exact same (for the most part). C-Up to accelerate upwards. C-Down to Hover.
--      There are 2 displays. A generic one and one that looks like the digital version from in game.
--      The digital one requires a specific font to work. To use it you will need "Quartz MS" Font.
--      You can download Quartz MS here: https://www.dropbox.com/s/u2np0mk6xmp67u7/QuartzMS.TTF?dl=0
--      On line 59 of this file there is a variable called "font", set this to true if you have Quarts MS Installed.
--      Otherwise leave it false for the generic display.
 
-- You should be a tribal when playing as Juno or Vela.
-- Sometimes this isn't applied but that't not really an issue.
-- For the Mizar's Palace Race you have to be a Drone so it is disabled there.
 
console.clear()
 
local font                  = false
 
-- Game Hash
versions                    = {
    ["493CED9008DBE932D6E91179B68E8630CF23A023"]    = "E",  -- English
    ["15099233760B36E7AFAD7DA36B9464DA1512C4B1"]    = "J"   -- Japanese
}
 
-- Version Detection
local v                 = versions[gameinfo.getromhash()]
if (v == "E") then
    gui.addmessage("Version: Jet Force Gemini (U)")
elseif (v == "J") then
    gui.addmessage("Version: Star Twins (J)")
else
    gui.addmessage("Version: Unknown")
    v = nil
end
 
local addrs                 = {
    ["E"]                   = {
        sceneLast           = 0x0A323C,
        sceneSetter         = 0x0A3250,
        entranceSetter      = 0x0A3258,
        loadFlag            = 0x0A3294,
        tribal              = {
            saved           = 0x1E6014,
            killed          = 0x1E6015,
            remaining       = 0x1E6016
        },
        region              = 0x0A3269,
        continues           = 0x0A3280,
        character           = 0x1E6010,
        model               = {
            vela            = 0x1E6170,
            juno            = 0x1E61E6
        },
        pointers            = { 
            vela            = 0x1D6BAC,
            juno            = 0x1D6BB4,
        },
        rainbow_blood       = 0x0A5080,
        paused              = 0x0A06A4,
        night_vision        = 0x0A6D03,
        lurg_vision         = 0x0A333B
    },
    ["J"]                   = {
        sceneLast           = 0x0A30FC,
        sceneSetter         = 0x0A3110,
        entranceSetter      = 0x0A3118,
        loadFlag            = 0x0A3154,
        tribal              = {
            saved           = 0x1E3584,
            killed          = 0x1E3585,
            remaining       = 0x1E3586
        },
        region              = 0x0A3129,
        continues           = 0x0A3140,
        character           = 0x1E3580,
        model               = {
            vela            = 0x1E36E0,
            juno            = 0x1E3756
        },
        pointers            = { 
            vela            = 0x1D40FC,
            juno            = 0x1D4104,
        },
        rainbow_blood       = 0x0A4F90,
        paused              = 0x0A0564,
        night_vision        = 0x0A6C13,
        lurg_vision         = 0x0A31FF
    },
    velocity                = {
        vela                = 0x0190,
        juno                = 0x0170
    },
    jet_fuel                = {
        vela                = 0x07B4,
        juno                = 0x0794
    },
    state                   = {
        vela                = 0x075A,
        juno                = 0x073A
    }
}
 
local playerVelocity        = nil
local playerFuel            = nil
local playerState           = nil
 
local timer                 = 0
local jetFuel               = 0
local jetFuelSwitch         = false
 
local tribals               = {
    saved                   = 0,
    killed                  = 0,
    remaining               = 0,
    killtotal               = 0
}
 
-- Initialize Version Dependant Variables
if (v ~= nil) then
    tribalRemaining         = addrs[v].tribal.remaining
    tribalKilled            = addrs[v].tribal.killed
    tribalSaved             = addrs[v].tribal.saved
    region                  = addrs[v].region
    continues               = addrs[v].continues
    sceneLast               = addrs[v].sceneLast
    sceneSetter             = addrs[v].sceneSetter
    entranceSetter          = addrs[v].entranceSetter
    loadFlag                = addrs[v].loadFlag
    rainbowBlood            = addrs[v].rainbow_blood
    paused                  = addrs[v].paused
    nightVision             = addrs[v].night_vision
    lurgVision              = addrs[v].lurg_vision
end
 
-- Encapsulate memory.read/write into functions.
function getByte(address)
    if (address ~= nil) then
        return memory.readbyte(address)
    else
        print("getByte(address): address (a nil value)")
    end
end
 
function getWord(address)
    if (address ~= nil) then
        return memory.read_u16_be(address)
    else
        print("getWord(address): address (a nil value)")
    end
end
 
function getDWord(address)
    if (address ~= nil) then
        return memory.read_u32_be(address)
    else
        print("getDWord(address): address (a nil value)")
    end
end
 
function setByte(address, value)
    if (address ~= nil and value ~= nil) then
        memory.writebyte(address, value)
    elseif (address == nil) then
        print("setByte(address, value): address (a nil value)")
    elseif (value == nil) then
        print("setByte(address, value): value (a nil value)")
    end
end
 
function setWord(address, value)
    if (address ~= nil and value ~= nil) then
        memory.write_u16_be(address, value)
    elseif (address == nil) then
        print("setWord(address, value): address (a nil value)")
    elseif (value == nil) then
        print("setWord(address, value): value (a nil value)")
    end
end
 
function setDWord(address, value)
    if (address ~= nil and value ~= nil) then
        memory.write_u32_be(address, value)
    elseif (address == nil) then
        print("setDWord(address, value): address (a nil value)")
    elseif (value == nil) then
        print("setDWord(address, value): value (a nil value)")
    end
end
 
-- This function handles setting up the player actor related data that moves around dynamically in memory.
function setupTribal()
 
    playerVelocity          = nil
    playerFuel              = nil
    playerState             = nil
 
    local character         = getByte(addrs[v].character)
    local model
 
    -- Check the character and set model to Tribal
    if (character == 0x00 or character == 0x04) then
        model               = getWord(addrs[v].model.vela) % 0x10
        model               = getWord(addrs[v].model.vela) - model
        setWord(addrs[v].model.vela, model + 0x02)
    elseif (character == 0x01 or character == 0x05) then
        model               = getWord(addrs[v].model.juno) % 0x10
        model               = getWord(addrs[v].model.juno) - model
        setWord(addrs[v].model.juno, model + 0x02)
    end
    
    -- Give the scene time to load
    for i = 0, 240, 1 do    -- 240 frames / 4 seconds.
        textDisplay()
        updateTribals()
        storeTribals()
        fixVision()
        emu.frameadvance()
    end
    
    -- Check the character and set addresses.
    if ((character == 0x00 or character == 0x04) and getDWord(addrs[v].pointers.vela) ~= 0x00000000) then
        playerVelocity      = getDWord(addrs[v].pointers.vela) - 0x80000000 + addrs.velocity.vela
        playerState         = getDWord(addrs[v].pointers.vela) - 0x80000000 + addrs.state.vela
        if (character == 0x04) then
            playerFuel          = getDWord(addrs[v].pointers.vela) - 0x80000000 + addrs.jet_fuel.vela
        end
    elseif ((character == 0x01 or character == 0x05) and getDWord(addrs[v].pointers.juno) ~= 0x00000000) then
        playerVelocity      = getDWord(addrs[v].pointers.juno) - 0x80000000 + addrs.velocity.juno
        playerState         = getDWord(addrs[v].pointers.juno) - 0x80000000 + addrs.state.juno
        if (character == 0x05) then
            playerFuel          = getDWord(addrs[v].pointers.juno) - 0x80000000 + addrs.jet_fuel.juno
        end
    end
 
end
 
-- Jet Pack with C-Up/C-Down like normal.
function levitate(i)
 
    if (playerVelocity ~= nil and playerFuel ~= nil and playerState ~= nil) then
    
        local fuel  = getWord(playerFuel)
        
        if (fuel > 0x0000 and fuel < 0x0E11 and getByte(playerState) ~= 0x01) then
            
            jetFuelSwitch   = true
            
            if (i == true) then
                setDWord(playerVelocity, 0x40A00000)        -- 5.0
                if (fuel - 0x0002 == 0xFFFF) then
                    setWord(playerFuel, 0x0000)
                else
                    setWord(playerFuel, fuel - 0x0002)
                end
            elseif (i == false) then
                setDWord(playerVelocity, 0x3FACCCCC)        -- 1.25
                setWord(playerFuel, fuel - 0x0001)
            end
            
        end
 
    end
 
end
 
-- This function handles updating the tribal counts.
function updateTribals()
 
    -- Store current counts to check against last frame's counts.
    local saved                 = getByte(tribalSaved)
    local killed                = getByte(tribalKilled)
    local remaining             = getByte(tribalRemaining)
    
    local savedDiff             = 0
    local killedDiff            = 0
 
    -- Check if the Remaining Tribals has gone down.
    if (remaining < tribals.remaining) then
        
        -- Killed Difference
        if (killed > tribals.killed) then
            killedDiff          = killed - tribals.killed
        elseif (killed < tribals.killed) then
            -- If the count has decreased then the player entered a new region.
            tribals.killed      = 0
        end
        
        -- Saved Difference
        if (saved > tribals.saved) then
            savedDiff           = saved - tribals.saved
        elseif (saved < tribals.saved) then
            -- If the count has decreased then the player entered a new region.
            tribals.saved       = 0
        end
        
        -- Apply Differences to opposite count.
        tribals.saved       = tribals.saved + killedDiff
        tribals.killed      = tribals.killed + savedDiff
        
        -- Update Kill Total
        tribals.killtotal   = tribals.killtotal + killedDiff
        
        -- Validate Tribal counts. (16 is highest)
        if (tribals.saved > 16 or tribals.killed > 16) then
            gui.addmessage("Invalid Tribal Counts")
            gui.addmessage("Reseting Counts...")
            setByte(tribalSaved, 0)
            setByte(tribalKilled, 0)
            setByte(tribalRemaining, tribals.remaining)
        else
            setByte(tribalSaved, tribals.saved)
            setByte(tribalKilled, tribals.killed)
        end
        
    end
 
end
 
-- Store the tribal counts.
function storeTribals()
 
    tribals.saved           = getByte(tribalSaved)
    tribals.killed          = getByte(tribalKilled)
    tribals.remaining       = getByte(tribalRemaining)
    
end
 
function jetFuelDisplayTimer()
 
    local fuel  = getWord(playerFuel)
    
    if (fuel ~= jetFuel) then
        jetFuelSwitch   = true
    elseif (fuel == 0x0000) then
        jetFuelSwitch   = false
    end
    
    if (jetFuelSwitch == true and timer < 455) then
        timer           = timer + 2
    elseif(jetFuelSwitch == false and timer > 0) then
        timer           = timer - 1
    end
    
    if (timer >= 455) then
        jetFuelSwitch   = false
    end
    
    jetFuel = fuel
 
end
 
function textDisplay() 
 
    local x     = 45
    local y     = 13
    local t     = 0
    
    if (timer < 0xFF) then
        t       = timer * 0x01000000
    else 
        t       = 0xFF000000
    end
 
    -- Tribal Counts
    if (getByte(loadFlag) == 0x00 and getByte(region) ~= 0x00 and getByte(paused) == 0x00) then
        if (getWord(sceneLast) ~= 0x0000 and
            getWord(sceneLast) ~= 0x0001 and
            getWord(sceneLast) ~= 0x007F and
            getWord(sceneLast) ~= 0x015C and
            getWord(sceneLast) ~= 0x015D and 
            getWord(sceneLast) ~= 0x017D and
            getWord(sceneLast) ~= 0x017E and
            getWord(sceneLast) ~= 0x017F and
            getWord(sceneLast) ~= 0x0180 and
            getWord(sceneLast) ~= 0x0181) then
            gui.drawBox(x, y, x + 102, y + 15, 0xFF4FB3C9, 0x80267580)
            gui.drawText(x - 2, y - 1, string.format("%02d", tribals.saved), 0x60FFFFFF, "TRANSPARENT", 16)
            gui.drawText(x + 22, y - 1, string.format("%02d", tribals.killed), 0x60FFFFFF, "TRANSPARENT", 16)
            gui.drawText(x + 46, y - 1, string.format("%02d", tribals.remaining), 0x60FFFFFF, "TRANSPARENT", 16)
            gui.drawText(x + 70, y - 1, string.format("%03d", tribals.killtotal), 0x60FFFF00, "TRANSPARENT", 16)
            gui.drawText(x - 2, y - 1, string.format("%2d", tribals.saved), 0xFFFFFFFF, "TRANSPARENT", 16)
            gui.drawText(x + 22, y - 1, string.format("%2d", tribals.killed), 0xFFFFFFFF, "TRANSPARENT", 16)
            gui.drawText(x + 46, y - 1, string.format("%2d", tribals.remaining), 0xFFFFFFFF, "TRANSPARENT", 16)
            gui.drawText(x + 70, y - 1, string.format("%3d", tribals.killtotal), 0xFFFFFF00, "TRANSPARENT", 16)
        end
    end
        
    -- Jet Fuel
    if (getByte(loadFlag) == 0x00 and getByte(paused) == 0x00 and playerFuel ~= nil and getWord(playerFuel) < 0x0E11) then
        
        if (font == false) then
        
            if (timer < 0x80) then
                gui.drawBox(x + 183, y + 424, x + 407, y + 439, t + 0x4FB3C9, t + 0x267580)
            else
                gui.drawBox(x + 183, y + 424, x + 407, y + 439, t + 0x4FB3C9, 0x80267580)
            end
            gui.drawText(x + 230, y + 423, string.format("Jet Fuel: %3d", getWord(playerFuel) / 36), t + 0xFFFFFF, "TRANSPARENT", 16)
        
        elseif (font == true) then
        
            -- Main
            if (getWord(playerFuel) / 36 == 100) then
                gui.drawText(470, 386, string.format("%3d", getWord(playerFuel) / 36), t + 0x00FF00, "Transparent", 47, "Quartz MS")
            elseif (getWord(playerFuel) / 36 >= 10) then
                gui.drawText(485, 386, string.format("%3d", getWord(playerFuel) / 36), t + 0x00FF00, "Transparent", 47, "Quartz MS")
            else
                gui.drawText(502, 386, string.format("%3d", getWord(playerFuel) / 36), t + 0x00FF00, "Transparent", 47, "Quartz MS")
            end
            
            -- Background
            if (timer < 0x20) then
                gui.drawText(470, 386, string.format("%3d", 888), t + 0x00FF00, "Transparent", 47, "Quartz MS")
            else
                gui.drawText(470, 386, string.format("%3d", 888), 0x2000FF00, "Transparent", 47, "Quartz MS")
            end
            
        end
        
    end
    
end
 
function fixVision()
 
    -- Disable Lurg Black Screen
    if (getByte(lurgVision) == 0x01) then
        setByte(lurgVision, 0x00)
    end
    
    -- 0x0107
 
    -- Disable Night Vision
    if (getByte(nightVision) ~= 0x00) then
        setByte(nightVision, 0x00)
    end
    
    -- By pass the Night Vision Room.
    -- Since it's disabled there's no reason to get it or activate it.
    if (getByte(loadFlag) ~= 0x00 and getWord(sceneSetter) == 0x013D and getWord(entranceSetter) == 0x0001) then
        setWord(sceneSetter, 0x0137)
    elseif (getByte(loadFlag) ~= 0x00 and getWord(sceneSetter) == 0x013C and getWord(entranceSetter) == 0x0000) then
        setWord(sceneSetter, 0x013B)
    end
 
end
 
-- Run this when the script is turned on. UNLESS at the title screen/game select menu.
if (getWord(sceneLast) ~= 0x0000 and
    getWord(sceneLast) ~= 0x0001 and
    getWord(sceneLast) ~= 0x007F and
    getWord(sceneLast) ~= 0x015C and
    getWord(sceneLast) ~= 0x015D and 
    getWord(sceneLast) ~= 0x017D and
    getWord(sceneLast) ~= 0x017E and
    getWord(sceneLast) ~= 0x017F and
    getWord(sceneLast) ~= 0x0180 and
    getWord(sceneLast) ~= 0x0181) then
    setupTribal()
    storeTribals()
end
 
while true do
 
    -- If version is not detected the script won't be able to do anything.
    if (v ~= nil) then
    
        -- Button Activators
        if joypad.get(1)['C Up'] then
            levitate(true)
        elseif joypad.get(1)['C Down'] then
            levitate(false)
        end
        
        -- On a load.
        if (getByte(loadFlag) ~= 0x00) then 
        
            local i = getWord(sceneSetter)
            -- If the entrance is any of the below this won't run.
            if (i ~= 0x0000 and     -- Game Select
                i ~= 0x0001 and     -- Game Select
                i ~= 0x007F and     -- Character Select
                i ~= 0x015C and     -- Title Screen
                i ~= 0x015D and     -- Title Screen
                i ~= 0x017D and     -- Title Screen
                i ~= 0x017E and     -- Title Screen
                i ~= 0x017F and     -- Title Screen
                i ~= 0x0180 and     -- Title Screen
                i ~= 0x0181 and     -- Title Screen
                i ~= 0x00FA and     -- Mizar's Palace Race Areas
                i ~= 0x010C and     -- Mizar's Palace Race Areas
                i ~= 0x011D and     -- Mizar's Palace Race Areas
                i ~= 0x0169 and     -- Mizar's Palace Race Areas
                i ~= 0x016B and     -- Mizar's Palace Race Areas
                i ~= 0x0197 and     -- Mizar's Palace Race Areas
                i ~= 0x018E and     -- Mizar's Palace Race Areas
                i ~= 0x018A) then   -- Mizar's Palace Race Areas
                
                -- Rainbow Blood
                setDWord(rainbowBlood, 0x01000000)  
                
                setupTribal()
                
            end
        end
        
        if (playerFuel ~= nil) then
            jetFuelDisplayTimer()
        end
        
        textDisplay()
        updateTribals()
        storeTribals()
        fixVision()
 
    end
    
    emu.frameadvance()
        
end

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎