User File #23370361143792947

Upload All User Files

#23370361143792947 - Daffy Duck - The Marvin Missions - Lua Script

Daffy Duck - The Marvin Missions.lua
753 downloads
Uploaded 6/10/2015 11:20 AM by Scepheo (see all 11)
--------------------------------------------------------------------------------
-- Daffy Duck - the Marvin Missions                                           --
--                                                                            --
-- Player & enemy data display                                                --
-- By: Scepheo                                                                --
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- Global constants                                                           --
--------------------------------------------------------------------------------

local ScreenWidth	= 160
local ScreenHeight	= 144

HelpOn = true
EnemiesOn = false
MapOn = false
PlayerOn = true

--------------------------------------------------------------------------------
-- Objects	                                                                  --
--------------------------------------------------------------------------------
Weapons = {
	"Original",
	"Rapid Fire",
	"Laser",
	"Bouncing",
	"Big Bullet"
}


function GetPlayer()
	local _player = {}
	memory.usememorydomain("HRAM")
	_player.X		= memory.read_u16_be(0x10)
	_player.Y		= memory.read_u16_be(0x12)
	_player.ScreenX	= memory.read_u8(0x14)
	_player.ScreenY	= memory.read_u8(0x15)
	_player.Lives	= memory.read_u8(0x18)
	_player.HP		= memory.read_u8(0x19)
	_player.SpeedX	= memory.read_s8(0x1B)
	_player.SpeedY	= memory.read_s8(0x1C)
	_player.Jet		= 19 - memory.read_u8(0x1E)
	
	-- TODO: find a better place for this
	_player.Tileset	= memory.read_u8(0x3B)
	
	memory.usememorydomain("WRAM")
	local score = memory.read_u8(0x00CF)
	_player.Score = bit.rshift(score, 4) * 10 + bit.band(score, 15)
	
	-- US
	--_player.Weapon	= Weapons[memory.read_u8(0x1009) + 1]
	-- EU
	_player.Weapon = Weapons[memory.read_u8(0x1012) + 1]
	
	return _player
end

function GetMap()
	local _map = {}
	
	memory.usememorydomain("HRAM")
	_map.Length		= memory.read_u8(0x0028)
	_map.Horizontal	= (memory.read_u8(0x0029) == 1)
	
	return _map
end

function GetTile(map, x, y)
	if (map.Horizontal) then
		return memory.read_u8(0x300 + x * 8 + y)
	else
		return memory.read_u8(0x300 + y * 10 + x)
	end
end

function GetEnemyAt(address)
	local _enemy = {}
		
	-- Uncollected ???
	-- Killed
	-- ???
	-- Falling ???
	
	-- Collectable
	-- Platform
	-- ???
	-- Direction
	
	-- 00 = 0000 0000 = Off screen (died)
	-- A0 = 1010 0000 = Normal dog
	-- C4 = 1100 0100 = Jumped dog
	-- 
	-- 89 = 1000 1001 = Normal heart
	-- 09 = 0000 1001 = Collected heart
	-- 81 = 1000 0001 = Normal turret (l&r)
	-- C1 = 1100 0001 = Shot turret (r) / Shot dog
	-- C0 = 1100 0000 = Shot turret (l) / Shot alarm
	-- 80 = 1000 0000 = Normal alarm / Marvin / Egg
	-- C5 = 1100 0101 = Jumped turret
	-- 84 = 1000 0100 = Normal platform / Normal "float"
	-- A4 = 1010 0100 = Used platform
	-- C4 = 1100 0100 = Shot "float"
	-- A1 = 1010 0001 = Normal raptor
	-- 91 = 1001 0001 = Rock
	-- 90 = 1001 0000 = Boss
	-- 11 = 0001 0001 = Fallen rock
	_enemy.State			= memory.read_u8(address + 0x0)
	_enemy.Active			= bit.band(_enemy.State, 0x80) == 0x80
	_enemy.Id				= memory.read_u8(address + 0x1)
	_enemy.X				= memory.read_u16_be(address + 0x2)
	_enemy.Y				= memory.read_u16_be(address + 0x4)
	_enemy.SpeedX			= memory.read_s8(address + 0x8)
	_enemy.SpeedY			= memory.read_s8(address + 0x9)
	_enemy.Invincibility	= memory.read_u8(address + 0xA)
	_enemy.HP				= memory.read_u8(address + 0xB) + 1
	_enemy.ScreenX			= memory.read_u8(address + 0xD)
	_enemy.ScreenY			= memory.read_u8(address + 0xE)
	
	_enemy.Number			= (address - 0x1F00) / 16
	return _enemy
end

function GetEnemyList()
	local _list = {}
	_list.Length = 0
	
	
	memory.usememorydomain("WRAM")
	
	for address = 0x1F00, 0x1FF0, 16 do
		local enemy = GetEnemyAt(address)
		_list[_list.Length] = enemy
		_list.Length = _list.Length + 1
	end
	
	return _list
end


--------------------------------------------------------------------------------
-- Map drawing                                                                --
--------------------------------------------------------------------------------

function DrawMap()
	local dx = Player.ScreenX - 8
	local dy = Player.ScreenY - 15
	
	local ScreenX = math.max(math.floor(Player.X / 16 - dx), 0)
	local ScreenY = math.max(math.floor(Player.Y / 16 - dy), 0)
	
	local offSetX = -(ScreenX % 16)
	local offSetY = -(ScreenY % 16)

	local xStart  = math.floor(ScreenX / 16)
	local yStart  = math.floor(ScreenY / 16)
	
	memory.usememorydomain("WRAM")
	for x = 0, 10 do
		for y = 0, 9 do
			DrawTile(xStart + x, yStart + y, offSetX + x * 16, offSetY + y * 16)
		end
	end
end

function DrawTile(xMap, yMap, xDraw, yDraw)
	if (yDraw >= 128) then
		return
	end
		
	local tile = GetTile(Map, xMap, yMap)
	local tileType = GetTileType(tile)
	
	local color
	
	if (tileType == FreeTile) then
		color = 0x0000FF
	elseif (tileType == WallTile) then
		color = 0x00FF00
	elseif (tileType == DoorTile) then
		color = 0xFFFF00
	elseif (tileType == KillTile) then
		color = 0xFF0000
	elseif (tileType == WarpTile) then
		color = 0xFF00FF
	end
		
	local foreColor = bit.bor(color, 0x99000000)
	local backColor = bit.bor(color, 0x66000000)
	
	gui.drawRectangle(xDraw, yDraw, 16, 16, foreColor, backColor)
	
	text(xDraw + 2, yDraw + 2, string.format("%X", tile))
end

FreeTile = 0
WallTile = 1
KillTile = 2
DoorTile = 3
WarpTile = 4

function GetTileType(tile)
	if (Player.Tileset == 2) then
	
		if (tile <= 60) then
			return FreeTile
		elseif (tile <= 76) then
			return WallTile
		elseif (tile <= 78) then
			return DoorTile
		else
			return WarpTile
		end
		
	elseif (Player.Tileset == 3) then
	
		if (tile <= 46) then
			return FreeTile
		elseif (tile <= 92) then
			return WallTile
		elseif (tile <= 95) then
			return KillTile
		elseif (tile <= 97) then
			return DoorTile
		else
			return WarpTile
		end
		
	elseif (Player.Tileset == 4) then
	
		if (tile <= 82) then
			return FreeTile
		elseif (tile <= 95) then
			return WallTile
		elseif (tile <= 97) then
			return DoorTile
		else
			return WarpTile
		end
	
	elseif (Player.Tileset == 5) then
	
		if (tile <= 60) then
			return FreeTile
		elseif (tile <= 79) then
			return WallTile
		elseif (tile <= 81) then
			return KillTile
		elseif (tile <= 97) then
			return DoorTile
		else
			return WarpTile
		end
		
	end
	
	return FreeTile
end
	

--------------------------------------------------------------------------------
-- GUI text drawing                                                           --
--------------------------------------------------------------------------------
local xScale, yScale, xOffset, yOffset

function Scale()
	xOffset = client.borderwidth()
	yOffset = client.borderheight()
	
	console.log('Offset: '..xOffset..'x'..yOffset)
	console.log('Buffer: '..client.bufferwidth()..'x'..client.bufferheight())
	console.log('Client: '..client.screenwidth()..'x'..client.screenheight())
	
	xScale = client.bufferwidth() / ScreenWidth
	yScale = client.bufferheight() / ScreenHeight
	
	console.log('Scale: '..xScale..'x'..yScale)
end

function text(x, y, text)
	gui.text(xOffset + x * xScale, yOffset + y * yScale, text, 0xFF000000, 0xFFFFFFFF)
end

function head(x, y, text)
	gui.text(xOffset + x * xScale, yOffset + y * yScale, text, 0xFF000000, 0xFF00FF00)
end

--------------------------------------------------------------------------------
-- Player data (over HUD)                                                     --
--------------------------------------------------------------------------------
function DrawHUD()
	gui.drawBox(0, 128, 160, 144, 0xFF000000, 0xFF000000)
	
	head(000, 129, "Player")
	text(000, 134, "HP: "    .. Player.HP)
	text(000, 139, "Lives: " .. Player.Lives)
	
	text(024, 134, "Jet: "   .. Player.Jet)
	text(024, 139, "Score: " .. Player.Score)

	head(048, 129, "Pos")
	text(048, 134, "X: " .. Player.X)
	text(048, 139, "Y: " .. Player.Y)

	head(072, 129, "Speed")
	text(072, 134, "X: " .. Player.SpeedX)
	text(072, 139, "Y: " .. Player.SpeedY)
	
	head(096, 129, "Global")
	text(096, 134, "Frame:  " .. emu.framecount())
	
	local weaponText = Player.Weapon or "---"
	text(096, 139, "Weapon: " .. weaponText)
end

--------------------------------------------------------------------------------
-- Camhack                                                                    --
--------------------------------------------------------------------------------
function CamHack()
	-- Simple overwrite of cam limit
	memory.usememorydomain("HRAM")
	memory.writebyte(0x0028, 255)
	
	-- Note that this does not allow for horizontal scrolling in vertical levels
	-- or vice-versa. I still need to find a way to achieve that.
end

--------------------------------------------------------------------------------
-- Enemy data                                                                 --
--------------------------------------------------------------------------------
function DrawEnemies()
	for i = 0, EnemyList.Length - 1 do			
		if (EnemyList[i].Active) then
			local x = EnemyList[i].ScreenX - 16
			local y = EnemyList[i].ScreenY - 24
			
			gui.drawRectangle(x, y, 16, 16, 0x80AA0000, 0x80AA0000)
			text(x, y +  4, "HP:" .. EnemyList[i].HP)
			text(x, y +  8, "X:"  .. EnemyList[i].X)
			text(x, y + 12, "Y:"  .. EnemyList[i].Y)
			text(x, y, EnemyList[i].Number)
			--text(x, y     , "HP:"  .. EnemyList[i].HP)
			--text(x, y + 4 ,	"Inv:" .. EnemyList[i].Invincibility)
			--text(x, y + 8 , "X:"   .. EnemyList[i].X)
			--text(x, y + 12, "Y:"   .. EnemyList[i].Y)
		end
	end
end

--------------------------------------------------------------------------------
-- Interface                                                                  --
--------------------------------------------------------------------------------

function DrawHelp()
	gui.text(8,  8, "Shortcut help")
	
	local y = 12
	
	for name in pairs(Input) do
		if (Input[name].On) then
			gui.text(8, y, Input[name].Key .. " - " .. name)
		else
			gui.text(8, y, Input[name].Key .. " - " .. name, 0xFF000000, 0xFFAAAAAA)
		end
		y = y + 16
	end
end

--------------------------------------------------------------------------------
-- Input                                                                      --
--------------------------------------------------------------------------------

Input = {}

Input["Help"] = {}
Input["Help"].Key = "H"
Input["Help"].Bind = DrawHelp
Input["Help"].On = false

Input["Enemies"] = {}
Input["Enemies"].Key = "E"
Input["Enemies"].Bind = DrawEnemies
Input["Enemies"].On = true

Input["Map"] = {}
Input["Map"].Key = "M"
Input["Map"].Bind = DrawMap
Input["Map"].On = true

Input["Player"] = {}
Input["Player"].Key = "S"
Input["Player"].Bind = DrawHUD
Input["Player"].On = true

lastInput = input.get()

function HandleInput()
	local input = input.get()
	
	for name, data in pairs(Input) do
		if (input[data.Key] and not lastInput[data.Key]) then
			Input[name].On = not Input[name].On
		end
	end	
	
	lastInput = input
end

--------------------------------------------------------------------------------
-- Main loop                                                                  --
--------------------------------------------------------------------------------
while true do
	Scale()
	--CamHack()
	
	Player = GetPlayer()
	Map = GetMap()
	EnemyList = GetEnemyList()
	
	HandleInput()
	
	for name in pairs(Input) do
		if (Input[name].On) then
			Input[name].Bind()
		end
	end
	
	emu.frameadvance()
end