61 users online:  Anorakun, autisticsceptile1993, Big Brawler, Blizzard Buffalo, BreadEater, brickblock369, bwal, chickaDEE Magazine, Cr4zy, crm0622, Daizo Dee Von, Dark Prince, Darolac,  Deeke, Doug Walker,  E-man38, EvanEMV, Fermín Acosta Jr., Green Jerry, Hat Kid, Hayashi Neru, Heraga, imamelia, Isaque World, kaigem, Katerpie, KiloMinimo,  Koopster, Kori, Leozoppi,  lion, lordkronos100, lucasfilm, Lunch Lunch, Lunming Gaming,  Maarfy, Mega,  Meirdent, MiracleWater, Mirann, Mr. MS, Murphmario, nahuelescoba, NGB, Pat, PilotStar, RAFAEL_M_C_, Raidenthequick, RetroJunky.T, Rilla Roo, S.N.N., SammmUuU,  Scrydan, SimFan96, Sokobansolver, Soonstar, Super Maks 64, TheMorganah, Ultima, Von Fahrenheit, Zerio - Guests: 93 - Bots: 299 Users: 45,651 (3,286 active)
Latest user: PilotStar
Not logged in.
Posts by thebevern
thebevern's Profile - Posts by thebevern
Pages: « 1 »
All the scripts and tools I have tested only seems to be detecting sprites such as enemies and intractable blocks.

Is there any script or way to get all the terrain block such as the floor, the climbable net, water and so on?

The goal is to be able to make path finding scripts and to have Mario move in other patterns when climbing.
Originally posted by Thomas
I'm a bit unsure about what you want to do, but if you're looking for how to read level data, you want $7EC800 and $7FC800, which contain all the tile data for the current level. Finding a specific tile can be a bit weird, though; if you need to do so through ASM, the routine from $019441 through $01953B might help (it finds the Map16 tile a sprite is currently touching, in a direction specified by Y with 0 = right, 1 = left, 2 = down, 3 = up).


I want to create a grid map of the entire level or a section of the level in a list. This map will be used for making path finding algorithm and specific behavior when mario is on a specific tiletype.

Your reply seems to be exactly what I am looking for so I will check it out thanks for the help.
I am using BizHawk with Lua-script and i have a function that gives me the block on an XY position

I sill can't solve how to read all terrain blocks into a list though. I'm trying to make one functions that gives me all the terrain blocks Mario can "see" and one that gives all blocks for the current level.

Got any hints, pointers or tutorial for this?
Originally posted by TheBiob
If you just want a list of blocks then all blocks are listed at 0x7EC800/0x7FC800.

This script has a function called "get_map16_value" which might be worth looking at.


Sweet thanks! What about water, lava and the climbable net are they part of the map_16 as well or?
Originally posted by TheBiob
Yes. Every block has it's own map16 id (I believe "map16" is just a name lunar magic gave it though). Water for example is 00 (01, 02 and 03 are also different types of water). Tiles 07-1C are climbable nets 06 is a vine, cement block is 130 etc.

If you open a clean rom in lunar magic then click on the "16x16 Tilemap editor" (#lm{16x}) you can see all tiles and their id. I believe "kind" contains the map16 id after calling the function from the script.


Nice then i have everything i need thank you all for the help.

One last question for this topic: do i manually have to sort out all the tiles that has an affect on Mario? For example water makes you swim but a tree is just for decoration.

Or is there a much simpler way?
Originally posted by TheBiob
As far as I know there is not. The original two pages are mostly sorted though (Like most of the blocks that are the same type are in a row)


I manually created a list of which of the first 512 tiles were interactable then i noticed it doesn't detect the water in the first water level (Yoshi's Island 4).

It can't be selected in the lunar magic editor either is it some sort of special case?
Ah i see! This different layer stuff feels a bit advanced and layer 1 is enough for what i want to do anyway.

Probably something i will look at once i learned more.
What i have tried so far:

Code
local camera_x = memory.readbyte(WRAM.camera_x)
local camera_y = memory.readbyte(WRAM.camera_y)
gui.drawLine(camera_x - node["tile"]["x"]*16, camera_y - node["tile"]["y"]*16, camera_x - nextNode["tile"]["x"]*16, camera_y - nextNode["tile"]["y"]*16, 0xFFFF1493)


But it gives me nothing. I am stuck trying to convert tile coordinates to screen coordinates and take the camera into consideration.

I have made a really basic pathfinding algorithm that i now want drawn on the screen so i can see that it works properly.

Here is an image for how i want it to look.



https://prnt.sc/gasbkm

mod edit: don't stretch tables. also fixed image
Originally posted by TheBiob
What exactly is in "node"?
Generally, to get the position on the screen all you really need to do is take the position and subtract the camera's position.

Code
local camera_x = memory.readbyte(WRAM.camera_x)
local camera_y = memory.readbyte(WRAM.camera_y)

local x_screen = x - camera_x
local y_screen = y - camera_y


Oh i'm stupid i made the coordinate and camera coordinate calculation in the wrong order. Your solution worked perfect thanks!
I'm using
Code
get_map16_value
function to get the
Code
num_x, num_y, kind, address

values of all tiles. But how do i check if a tile is solid or not (tiles that Mario can go through). Every level has a unique tileset so i can't map them up manually with Lunarmagic.
Originally posted by Thomas
Not entirely sure which function that's referring to, it'd help to start there.

If "kind" refers to the "acts like" setting in LM, then that's probably what you'd use, though. You can determine whether a tile is solid or not based on that.
Tiles in the range 100-110 are ledges, 111-16B are solid, 16E-1D7 are slopes, and 1D8-1FF are slope assists (i.e. corners).
Tiles in the 000-0FF range are generally non-solid, except for certain tileset-specific tiles. Check in each of the graphical headers (under #lm{gfxby}) for those.

Note that custom blocks can programatically change the acts-like setting during gameplay, though, so depending on when you're running this code, it may not necessarily be accurate.


get_map16_value is copied from:
https://github.com/rodamaral/smw-tas/blob/master/snes9x/scripts/smw-snes9x.lua

Thats the problem "generally" becomes a bit of a pain (if we ignore those that can change during gameplay). Isn't there a way to check if a tile has a hitbox or something easier?
Originally posted by Thomas
Not really, there's no hitbox flag or anything; the acts-like is your only way. That, combined with the tileset setting in $1931, are the only values that the game uses to decide whether or not the tile is solid.
(for what it's worth, the tileset-specific tiles only are form 073-0FF, and most of the time they're non-solid; only exception I can think of is 0EC-0FB in Switch Palace 1/Ghost House 1/2)

I took a look at the lua script you linked, though, and it appears "kind" only refers to the Map16 tile number itself and not the acts-like setting. For tiles 000-1FF, this is fine, since they're always set to act like themselves. For 200-7FFF (i.e. custom Map16), though, that value won't help. See the Acts-Like setting here for details on how to turn that into a value from 000-1FF.




It seems that "kind" for the vertical wall returns 37 which is just a standard empty block but its clearly a solid wall there. Is that a layer related issue or is the wall not a tile.
Lunarmagic has a "Tile Surface Outlines" under the view menu. Any idea how it calculates that? It looks like exactly what i need.
Alright i think i got the hang of it now. However is struggle with debugging to see if i done it right. I attached an image in a reply above where i am drawing debug data on the screen. The problem is due to how the camera works it keeps redrawing the first 16 solid tiles.

Code
for key,node in pairs(levelData.pathToGoal) do
          local index, nextNode = next(levelData.pathToGoal, key)
          if nextNode then
			local camera_x = memory.readbyte(WRAM.camera_x)
			local camera_y = memory.readbyte(WRAM.camera_y)

			local screen_x = node["tile"]["x"] - camera_x
			local screen_y = node["tile"]["y"] - camera_y
			
			local screen_x2 = nextNode["tile"]["x"] - camera_x
			local screen_y2 = nextNode["tile"]["y"] - camera_y
			 
			gui.drawLine(screen_x, screen_y, screen_x2, screen_y2, 0xFFFF1493)
			gui.drawText(screen_x, screen_y, node["tile"]["x"], 0xFF000000, 10)
          end
        end


I have not managed to make working code for converting my global tile coordinates to local camera coordinates. Since the camera_x and camera_y resets when it enters a new screen. So it just repeat the draw from the previous screen.
Originally posted by randomdude999
camera_x and camera_y probably reset after the first screen because you forgot to read their high byte. I'm not familiar with whatever the API for snes9x-rr is, but there's probably a function called readword too, you should use that one for word values like the camera position.


Yes of course that was exactly the problem thanks
Looping through all local sprites is no problem (i found existing code for that) but if you want all sprites globally is that possible? More specifically i want their X,Y positions and which sprite it is.

Are non loaded sprites even available before entering their spawn/init zone?
Originally posted by Thomas
It's possible to check the actual level data at least. $CE contains a 24-bit pointer to the current level's sprite data. You can find information on the actual format of that data over here.


Sounds promising. I am not sure how to loop through them all with lua. Since it is a 24bit pointer is it some sort of special case? Or can i just start at that address then loop through the sprite data 3 byte at the time until the end address is reached?

Is there any example/sample code somewhere?
Here is what i attempted so far:

Code
  local spritesPointerAddress = memory.read_u24_le(WRAM.sprite_data_pointer) + 0x0
  
  for i=1,256 do
    --First 4 bits for spriteX and spriteY
	local spriteX = bit.band(memory.readbyte(spritesPointerAddress+i), 0x0F)
	local spriteY = bit.band(memory.readbyte(spritesPointerAddress+i+1), 0x0F)
	local spriteNumber = memory.readbyte(spritesPointerAddress+i+2)
  	local spriteData = {["x"]=spriteX, ["y"]=spriteY, ["kind"]=2, ["address"]=spriteNumber,}
    table.insert(levelData.tileMap, spriteData)
  end


This will just give me nonsense data is this on the right track and i just made some small mistakes?
Code
for i=1,256,3 do
    --First 4 bits for spriteX and spriteY
	if (i < 253) then
		local yAdress = memory.readbyte(spritesPointerAddress+i)
		local xAdress = memory.readbyte(spritesPointerAddress+i+1)
	
		local spriteY = bit.lshift(bit.band(yAdress, 0x01), 8) + bit.band(yAdress, 0xF0)
		local spriteX = bit.lshift(bit.band(yAdress, 0x02), 11) + bit.lshift(bit.band(xAdress, 0x0F), 8) + bit.band(xAdress, 0xF0)
		local spriteNumber = memory.readbyte(spritesPointerAddress+i+2)
		local spriteData = {["x"]=spriteX, ["y"]=spriteY, ["kind"]=spriteNumber, 
			["address"]=string.format(" $%4.x", spritesPointerAddress+i),["isSprite"]=true,}
		table.insert(levelData.tileMap, spriteData)
	end
  end


Updated the code to this based on your pseudo code.

The values emitted makes more sense but when checking in Lunar Magic some sprites have XY coordinate far up in the sky were no sprite is ever present. I think its very close to being correct but something is still a bit off
Originally posted by Thomas
Your error is probably from still having an incorrect terminating condition. You should be explictly checking for the FF end byte to mark the end of the data. If you don't, you'll keep reading in invalid sprites.

Here's an example with my code showing you what you should be getting for level 105, if that helps. You can validate the numbers against LM.


Code
  local spritesPointerAddress = memory.read_u24_le(WRAM.sprite_data_pointer) + 0x0
  local i = 1
  
  while memory.readbyte(spritesPointerAddress+i) ~= 0xFF do
	local yAdress = memory.readbyte(spritesPointerAddress+i)
	local xAdress = memory.readbyte(spritesPointerAddress+i+1)
	--https://www.smwcentral.net/?p=viewthread&t=98597&page=1&pid=1509061#p1509061
	local spriteY = bit.lshift(bit.band(yAdress, 0x01), 8) + bit.band(yAdress, 0xF0)
	local spriteX = bit.lshift(bit.band(yAdress, 0x02), 11) + bit.lshift(bit.band(xAdress, 0x0F), 8) + bit.band(xAdress, 0xF0)
	local spriteNumber = memory.readbyte(spritesPointerAddress+i+2)
	local spriteData = {["x"]=spriteX, ["y"]=spriteY, ["kind"]=spriteNumber, 
		["address"]=string.format(" $%4.x", spritesPointerAddress+i),["isSprite"]=true,}
	print(spriteData)
	table.insert(levelData.tileMap, spriteData)
	i = i + 3
  end


You were right thanks. When i changed the final code to the one above the output matches the one for level 105 exactly. Are they XY values swapped for vertical levels?
Pages: « 1 »
thebevern's Profile - Posts by thebevern