View Single Post
Old 08-24-2018, 11:44 AM   #7
crazygerry
Junior Member
 
Join Date: Jul 2018
Posts: 3
Default Sim City with mouse

Quote:
Originally Posted by king killa View Post
I <3 the internet
If you like mouse supporton lemmings, maybe you like SimCity with mouse, too ;-)

lua is not very popular by newer emulators. It's a pity.
I would vote for it :-)

Code:
print("SimCity grid viewer, for snes9x-rr 1.43 ~ 1.51")
print("written by Dammit, 2/21/2009 ~ 6/2/2011") --dammit9x at hotmail dot com
print("mouse support by crazygerry 2018")
print("tested with: https://github.com/gocha/snes9x/ 1.53 ~ 1.55")
--(old) use with: http://code.google.com/p/snes9x-rr/
--purpose: display land values and other parameters on the playfield for the SimCity game
--discussion: http://tasvideos.org/forum/viewtopic.php?p=192582#192582

local hotkey = { --hotkey settings
	mode_inc    = {"K", "cycle view modes forward (or middleclick)"},
	mode_dec    = {"L", "cycle view modes backward"},
	show_values = {"U", "show/hide grid values"},
	show_grid   = {"I", "show/hide the grid"},
	show_coords = {"O", "show/hide the map coordinates and city center"},
	num_format  = {"P", "switch between decimal & hex numbers"},
}

local globals = { --initial settings
	view_mode   = 1,
	show_values = true,
	show_grid   = true,
	show_coords = false,
	hex_numbers = false,
	use_mouse = true,
}

local label_x, label_y = 128, 216 --where to draw the view mode label
local coord_x, coord_y = 216, 216 --where to draw the map coordinates

local color = {
	["level 8"]     = 0xFF0000, --these are the in-game map colors
	["level 7"]     = 0xFF6300,
	["level 6"]     = 0xFFB500,
	["level 5"]     = 0xFFFF00,
	["level 4"]     = 0x00FF00,
	["level 3"]     = 0x00BD00,
	["level 2"]     = 0x008C00,
	["level 1"]     = 0x005A00,
	["powered"]     = 0xFF8400,
	["unpowered"]   = 0x00B500,
	["city center"] = 0xFF00FF,
	["dec text"]    = 0xFFFFFF, --grid values in decimal mode
	["hex text"]    = 0xFFFF00, --grid values in hexadecimal mode
	["label text"]  = 0x00FF00, --view mode label text
	["coord text"]  = 0x00FFFF, --coordinate text
}

local opacity = {
	fill    = 0x20, --inside of boxes
	outline = 0xA0, --outside of boxes
	text    = 0xFF,
}

--------------------------------------------------------------------------------

--prepare color settings
local fill, outline = {}, {}
local function map_colors(index, name)
	fill[index]    = bit.lshift(color[name], 8) + opacity.fill
	outline[index] = bit.lshift(color[name], 8) + opacity.outline
end

for i = 0xFF, 0, -1 do
	if i > 0xE0 then map_colors(i, "level 8")
	elseif i > 0xC0 then map_colors(i, "level 7")
	elseif i > 0xA0 then map_colors(i, "level 6")
	elseif i > 0x80 then map_colors(i, "level 5")
	elseif i > 0x60 then map_colors(i, "level 4")
	elseif i > 0x40 then map_colors(i, "level 3")
	elseif i > 0x20 then map_colors(i, "level 2")
	elseif i > 0x00 then map_colors(i, "level 1")
	else
		fill[i]    = 0 --blank/transparent
		outline[i] = 0
	end
end
map_colors(true, "powered")
map_colors(false, "unpowered")
map_colors("city center", "city center")
fill["dec text"]   = bit.lshift(color["dec text"], 8) + opacity.text
fill["hex text"]   = bit.lshift(color["hex text"], 8) + opacity.text
fill["label text"] = bit.lshift(color["label text"], 8) + opacity.text
fill["coord text"] = bit.lshift(color["coord text"], 8) + opacity.text

--memory addresses
local address = {
	x_tile   = 0x7E01BD, --camera position by upper-left tile
	y_tile   = 0x7E01BF,
	x_center = 0x7E0BA9, --coordinate of the city center
	y_center = 0x7E0BAA,
	playing  = 0x7E0012, --a game is in progress: draw coords
	hud      = 0x7E2210, --in-game HUD is shown: don't draw grid
	dark     = 0x7E90FF, --darkened BG: don't draw grid
	magnify  = 0x7E019B, --magnifier tool is open: draw grid
	time     = 0x7E0B51, --increments four times per game month; currently unused
	x_cursor = 0x7E01EB,
	y_cursor = 0x7E01ED,
	taxind   = 0x7E2016, -- holds some values to identify tax screen
}

--parameter values are stored here
local view = {
	{address = 0x7F6B00, sqsize = 2, bytes = 1, name = "Land value"},
	{address = 0x7F76B8, sqsize = 2, bytes = 1, name = "Crime"},
	{address = 0x7F8270, sqsize = 2, bytes = 1, name = "Pollution"},
	{address = 0x7F8E28, sqsize = 2, bytes = 1, name = "Population density"},
	{address = 0x7F99E0, sqsize = 2, bytes = 1, name = "Traffic"},
	{address = 0x7FA598, sqsize = 1, bytes = 1/8, name = "Power"},
	{address = 0x7FAB74, sqsize = 4, bytes = 1, name = "Land value modifier"},
	{address = 0x7FAE62, sqsize = 8, bytes = 2, name = "Growth rate"},
	{address = 0x7FAFE8, sqsize = 8, bytes = 1, name = "Police coverage"},
	{address = 0x7FB0AB, sqsize = 8, bytes = 1, name = "Fire coverage"},
}

local screenwidth, screenheight, tilesize = 256, 224, 8 --size in pixels
local mapwidth, mapheight = 120, 100 --size in tiles
local pressing_old = {} --array for keyboard input

for _, mode in ipairs(view) do
	mode.y_step = mapwidth / mode.sqsize
	mode.read = mode.bytes == 2 and memory.readwordsigned or memory.readbyte
end

print()
print("To enable the grid, hide the HUD with button Y or open the magnifier.")
print()
for _, v in pairs(hotkey) do
	print("Press the '" .. v[1] .. "' key to " .. v[2] .. ".")
end

function bit(p) --http://lua-users.org/wiki/BitwiseOperators
	return 2 ^ (p - 1)
end

function hasbit(x, p)
	return x % (p + p) >= p
end

local function draw_boxes()
	local x_tile, y_tile, mode = globals.x_tile, globals.y_tile, view[globals.view_mode]
	local y = 0
	while y < screenheight do
		local y_next = y + mode.sqsize * tilesize
		if y == 0 then
			y_next = (mode.sqsize - y_tile % mode.sqsize) * tilesize
		end
		if y_next > screenheight then
			y_next = screenheight
		end
		local x = 0
		while x < screenwidth do
			local x_next = x + mode.sqsize * tilesize
			if x == 0 then
				x_next = (mode.sqsize - x_tile % mode.sqsize) * tilesize
			end
			if x_next > screenwidth then
				x_next = screenwidth
			end
			if x_tile + x/tilesize >= 0 and y_tile + y/tilesize >= 0 --check the map boundaries
			and x_tile + x/tilesize < mapwidth and y_tile + y/tilesize < mapheight then
				local value = mode.read(mode.address + math.floor(
				(math.floor((x_tile + x/tilesize) / mode.sqsize)
				+ math.floor((y_tile + y/tilesize) / mode.sqsize) * mode.y_step) * mode.bytes))

				if globals.show_grid then
					if mode.read == memory.readwordsigned then
						if value > 0xFF then value = 0xFF end
						if value < -0xFF then value = -0xFF end
						value = math.floor((value + 0xFF) / 2)
					end
					if mode.bytes < 1 then
						value = hasbit(value, bit(8 - (x_tile + x/tilesize + (y_tile + y/tilesize) * mode.y_step) % 8))
					end
					gui.box(x, y, x_next-1, y_next-1, fill[value], outline[value])
				end

				if globals.show_values and value ~= 0 and mode.sqsize > 1 and
					x_next >= 2 * tilesize and y_next >= 2 * tilesize and
					x + 2 * tilesize <= screenwidth and y + 2 * tilesize <= screenheight then
					local color
					if globals.hex_numbers then
						value, color = string.format("%02X", value), fill["hex text"]
					else
						value, color = string.format("%d", value), fill["dec text"]
					end
					gui.text(x_next - value:len() * 4 - 1, y + 1, value, color)
				end

			end
			x = x_next
		end
		y = y_next
	end

	if globals.show_grid or globals.show_values then --show the label only with the grid or values active
		gui.text(label_x, label_y, mode.name, fill["label text"])
	end
end

local function draw_data()
	local x_tile, y_tile, x_center, y_center = globals.x_tile, globals.y_tile, globals.x_center, globals.y_center
	if globals.grid_ok then
		draw_boxes()
	end

	if globals.show_coords then --show the coordinates & city center
		if globals.use_mouse == false then
			gui.text(coord_x, coord_y, "(" .. x_tile .. ", " .. y_tile .. ")", fill["coord text"])
		end

		local xdraw, ydraw = (x_center - x_tile) * tilesize, (y_center - y_tile) * tilesize
		if x_center < x_tile then
			xdraw = 0
		end
		if x_center >= x_tile + screenwidth/tilesize then
			xdraw = screenwidth - tilesize
		end
		if y_center < y_tile then
			ydraw = 0
		end
		if y_center >= y_tile + screenheight/tilesize then
			ydraw = screenheight - tilesize
		end
		gui.box(xdraw, ydraw, xdraw + 7, ydraw + 7, fill["city center"], outline["city center"])
	end
end

local function mouse_support(inp)
	local taxscreenindicatorvalue = memory.readbyte(address.taxind)
	local taxscreenindicatorvalues = {131,133,135,137,139,141,195,197,199,201}
	local taxscreenvisible, movemap = false, false
	local pad = joypad.get(1)
	local x_mousepos, y_mousepos = math.floor(inp.xmouse/8), math.floor(inp.ymouse/8)
	local x_mouseonmap, y_mouseonmap = x_mousepos + memory.readbytesigned(address.x_tile), y_mousepos + memory.readbytesigned(address.y_tile)
	for i = 1, 10 do
		if taxscreenindicatorvalues[i] == taxscreenindicatorvalue then taxscreenvisible = true break end
	end
	if taxscreenvisible == false then	
		if(x_mouseonmap >= 0 and x_mouseonmap < mapwidth and y_mouseonmap >= 0 and y_mouseonmap < mapheight) then
			gui.text(coord_x, coord_y, "(" .. x_mouseonmap+1 .. ", " .. y_mouseonmap+1 .. ")", fill["coord text"])		
		end
		if(x_mouseonmap >= -6 and x_mouseonmap < mapwidth+6 and y_mouseonmap >= -6 and y_mouseonmap < mapheight+6) then
			memory.writebyte(address.x_cursor,x_mousepos*8)
			memory.writebyte(address.y_cursor,y_mousepos*8)			
		end
		if(inp.xmouse > 232) then memory.writebyte(address.x_cursor,232) end
		if(inp.xmouse < 16) then memory.writebyte(address.x_cursor,16) end
		if(inp.ymouse > 192) then memory.writebyte(address.y_cursor,192) end
		if(inp.ymouse < 24) then memory.writebyte(address.y_cursor,24) end
	end
	if (inp.xmouse >= screenwidth-1) then movemap, pad.right = true, true joypad.set(1,pad) end
	if (inp.xmouse <= 0) then movemap, pad.left = true, true joypad.set(1,pad) end
	if (inp.ymouse >= screenheight-1) then movemap, pad.down = true, true joypad.set(1,pad) end
	if (inp.ymouse <= 0) then movemap, pad.up = true, true joypad.set(1,pad) end
	if (movemap and inp.leftclick == false) then pad.Y = true end
	if (inp.leftclick) then pad.B = true joypad.set(1,pad) end
	if (inp.rightclick) then pad.X = true joypad.set(1,pad) end
end

emu.registerafter(function()
	globals.game_playing = memory.readbyte(address.playing) > 0
	if not globals.game_playing then
		pressing_old = {}
		return
	end

	globals.grid_ok = memory.readbyte(address.dark) == 0 and 
		(memory.readword(address.hud) == 0x5555 or memory.readbyte(address.magnify) > 0)
	globals.x_tile, globals.y_tile = memory.readbytesigned(address.x_tile), memory.readbytesigned(address.y_tile)
	globals.x_center, globals.y_center = memory.readbyte(address.x_center), memory.readbyte(address.y_center)
	
	local pressing = input.get()
	
	if (globals.show_grid or globals.show_values) and globals.grid_ok then
		if (pressing[hotkey.mode_inc[1]] or pressing.middleclick) and not (pressing_old[hotkey.mode_inc[1]] or pressing_old.middleclick) then
			globals.view_mode = globals.view_mode >= #view and 1 or globals.view_mode + 1
		elseif pressing[hotkey.mode_dec[1]] and not pressing_old[hotkey.mode_dec[1]] then
			globals.view_mode = globals.view_mode == 1 and #view or globals.view_mode - 1
		end
	end
	if pressing[hotkey.show_values[1]] and not pressing_old[hotkey.show_values[1]] and globals.grid_ok then
		globals.show_values = not globals.show_values
	end
	if pressing[hotkey.show_grid[1]] and not pressing_old[hotkey.show_grid[1]] and globals.grid_ok then
		globals.show_grid = not globals.show_grid
	end
	if pressing[hotkey.show_coords[1]] and not pressing_old[hotkey.show_coords[1]] then
		globals.show_coords = not globals.show_coords
	end
	if pressing[hotkey.num_format[1]] and not pressing_old[hotkey.num_format[1]] and globals.show_values then
		globals.hex_numbers = not globals.hex_numbers
	end

	pressing_old = pressing
end)

gui.register(function()
	if globals.game_playing then
		draw_data()
		if globals.use_mouse then
			mouse_support(input.get())
		end
	end
end)
Have fun !
crazygerry is offline   Reply With Quote