Views: 773,058,471Time: 2019-08-24 11:05:31 PM 21 users online: Adryel, , earthmeLon, eltiolavara9, Evernn, GreenHammerBro, Kiatus, , marathonx, Maxodex, NikSik1, pakkie, placeholdertest, , slothrop, The X, TooMuchToby, umjammercammy, WhiteYoshiEgg, Yoshin, Zandro - Guests: 50 - Bots: 209 Users: 40,602 (1,831 active)Latest: Overcrow
 Tip: Check this thread to find extremely useful diagrams and data. Not logged in.
Advanced Documentation and ASM Code Library
Forum Index - SMW Hacking - SMW Hacking Help - ASM & Related Topics - Advanced Documentation and ASM Code Library
 Pages: 1 2 3 4 5 6 7 8
.. Yes, that's what I said.
It's not the center, it's the sprite position. The ones in RAM.

--------------------
Thats why I put them in quotes, they move relatively to each other.

--------------------
Give thanks to RPG hacker for working on Asar.
I realized, that mine is "glitch proof", meaning that there is a bug on smw's clipping routine when a sprite's hitbox is past the left edge of the level (mainly, the banzai bill). Since Mine is signed position but not smw, this is better (minus the 16-bit width and height).

E: I was wrong, it uses a different collision routine that had a bug.

--------------------
Give thanks to RPG hacker for working on Asar.

Because the Hex -> Dec (long) was very complicated to use when you want it to display 4 (or rarely 5) digits. I made a simple subroutine that does all the work for you. It works by dividing the value by 10 repeatedly and taking the remainder for each digits starting at “low digit”, here is an example:

Code
```\$1234 is 4660 in decimal:

\$1234/\$A = Q:\$1D2 R:\$0 (ones place)

\$1D2/\$A = Q:\$2E R:\$6 (tens place)

\$2E/\$A = Q:\$4 R:\$6 (hundreds place)

\$4/\$A = Q:0 R:\$4 (thousands place)```

Obviously, this converts a binary integer into unpacked Binary coded decimal due to each digit placed in each byte.

Code
```;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;16-bit hex to 4 (or 5)-digit decimal subroutine
;Input:
; \$00-\$01 = the value you want to display
;Output:
; !HexDecDigitTable to !HexDecDigitTable+4 = a digit 0-9 per byte table
; (used for 1-digit per 8x8 tile):
; +\$00 = ten thousands
; +\$01 = thousands
; +\$02 = hundreds
; +\$03 = tens
; +\$04 = ones
;
;!HexDecDigitTable is address \$02 for normal ROM and \$04 for SA-1.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if read1(\$00FFD5) == \$23	;\can be omitted if pre-included
!sa1 = 1
sa1rom
else
!sa1 = 0
endif				;/

!HexDecDigitTable = \$02
if !sa1 != 0
!HexDecDigitTable = \$04
endif

ConvertToDigits:
if !sa1 == 0
PHX
PHY

LDX #\$04	;>5 bytes to write 5 digits.

.Loop
REP #\$20	;\Dividend (in 16-bit)
LDA \$00		;|
STA \$4204	;|
SEP #\$20	;/
LDA.b #10	;\base 10 Divisor
STA \$4206	;/
JSR .Wait	;>wait
REP #\$20	;\quotient so that next loop would output
LDA \$4214	;|the next digit properly, so basically the value
STA \$00		;|in question gets divided by 10 repeatedly. [Value/(10^x)]
SEP #\$20	;/
LDA \$4216	;>Remainder (mod 10 to stay within 0-9 per digit)
STA \$02,x	;>Store tile

DEX
BPL .Loop

PLY
PLX
RTL

.Wait
JSR ..Done		;>Waste cycles until the calculation is done
..Done
RTS
else
PHX
PHY

LDX #\$04

.Loop
REP #\$20			;>16-bit XY
LDA.w #10			;>Base 10
STA \$02				;>Divisor (10)
SEP #\$20			;>8-bit XY
JSL MathDiv			;>divide
LDA \$02				;>Remainder (mod 10 to stay within 0-9 per digit)
STA.b !HexDecDigitTable,x	;>Store tile

DEX
BPL .Loop

PLY
PLX
RTL
endif

if !sa1 != 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; unsigned 16bit / 16bit Division
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Arguments
; \$00-\$01 : Dividend
; \$02-\$03 : Divisor
; Return values
; \$00-\$01 : Quotient
; \$02-\$03 : Remainder
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MathDiv:	REP #\$20
ASL \$00
LDY #\$0F
LDA.w #\$0000
-		ROL A
CMP \$02
BCC +
SBC \$02
+		ROL \$00
DEY
BPL -
STA \$02
SEP #\$20
RTL
endif```

Code
```	RemoveLeadingZeroes:
LDX #\$00

.Loop
LDA !DigitTable,x	;\if current digit non-zero, don't omit trailing zeros
BNE .NonZero		;/
LDA #\$FC		;\blank tile to replace leading zero
STA !DigitTable,x	;/
INX			;>next digit
CPX #\$04		;>last digit to check (tens place). So that it can display a single 0.
BCC .Loop		;>if not done yet, continue looping.

.NonZero
RTL```

2/23/2018 edit: improved the loop code for the hexdec routine so that after writing the last digit, doesn't do unnecessary division once again before breaking out the loop. Also you can now go above 32,767 for both versions without issues.

4/20/2018 edit: renamed the !Sa1 to !sa1 to fit with many patches (and tools) that nowdays uses the “ all lowercase” defines.

3/24/2019 edit: rename the define.

--------------------
Give thanks to RPG hacker for working on Asar.
I happen to have needed a similar function for some VLDC shenanigans. If anyone cares, this is the code I used:
Possible advantages: It works in non mirrored RAM, use of pointer for where to store decimal value, works for full range 0...65535 (#\$0000-#\$FFFF)
Possible disadvantages: Worst case (dec value 59999) the loop is executed 41 times each costing some 48 cycles.

Code
```;A   = 16 bit value to convert
;\$00 = long pointer to where decimal should be stored
PrintCounter:
LDY #\$04
LDX #\$06
-
CMP.l .decimal,x	; \ branch if value is less than 10^(x/2+1)
BCC +			; /
PHA			; \
SEP #\$20		; |
LDA [\$00],y		; |
INC			; | increase current position
STA [\$00],y		; |
REP #\$20		; |
PLA			; /
SEC			; \
SBC.l .decimal,x	; | subtract 10^(x/2+1)
BRA -			; / and repeat loop
+
DEY			; set pointer to next (previous) position
DEX : DEX		; get to next decimal digit
BPL -			; loop while x is positive (or 0)
RTS			; return

.decimal:
dw \$000A	;    10
dw \$0064 	;   100
dw \$03E8	; 1.000
dw \$2710	;10.000```

--------------------
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
signed sine and signed cosine:
Code
```;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;GreenHammerBro's signed sine routine.
;Input:
;\$00-\$01 : The degree value (#\$0000-#\$01FF)
;Output:
;\$02-\$03 : Signed sine result.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SignedSine:
PHX
REP #\$30
LDA \$00			;>Input
AND #\$00FF		;>Remove high byte (since index is 0-255)
ASL			;>Each value holds 2 bytes.
TAX			;>Transfer to index.
STA \$02			;>The unsigned result stored.
SEP #\$30

.FlipIfNegative
LDA \$01			;\If degree value is >= #\$0100 (180 in real-word
BEQ ..Positive		;/degrees), then don't flip the end result
REP #\$20		;\Flip
LDA \$02			;|
EOR #\$FFFF		;|
INC			;|
STA \$02			;|
SEP #\$20		;/

..Positive
PLX
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;GreenHammerBro's signed cosine routine.
;Input:
;\$00-\$01 : The degree value (#\$0000-#\$01FF)
;Output:
;\$02-\$03 : Signed cosine result.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SignedCosine:
PHX
REP #\$30
LDA \$00			;\Shift by 90 real world degrees
CLC			;|(since cosine is sine+90)
CMP #\$0100		;\If bigger than 180 (real world) degrees,
BCC .FirstHalf		;/loop back to index 0 with the 2nd half.
CMP #\$0200		;\If approaching final quadrant, don't invert
BCS .FirstHalf		;/

.SecondHalf		;>#\$0100 to #\$01FF = 2nd half (negative X)
AND #\$00FF		;>Modulo by 256 (#\$0100, because smw only have half-wave)
ASL			;>Each value holds 2 bytes.
TAX			;>Transfer to index.
EOR #\$FFFF		;\Invert
INC A			;/
STA \$02			;>And get negative X value.
SEP #\$30
BRA .Done

.FirstHalf	;>#\$0000-#\$00FF or #\$0200-#\$02FF (positive X)
AND #\$00FF	;>Remove high byte (if final quadrant)
ASL		;>Each value holds 2 bytes.
TAX		;>Transfer to index.
STA \$02
SEP #\$30

.Done
PLX
RTS```

Made this from scratch. Things to note:
• Smw's "unit circle" is multiplied by 256 to allow fractional units, since values are regarded as integers.
• To convert smw <-> real world degrees, here is the formula: Real world to smw's: SMWDegrees = RealWorldDegrees*512/360.
To convert to real world: RealWorldDegrees = SMWDegrees*360/512

--------------------
Give thanks to RPG hacker for working on Asar.

Doesn't that already exist at \$01CB20? The only difference is that it's not inverted when negative, but you can determine that from \$1866/\$1867.

Professional frame-by-frame time wizard. YouTube - Twitter - SMW Glitch List - SMW Randomizer
Due to some bugs found with changing multiple map16 blocks, I found a glitch with the behavor as well as interacting with 2 blocks at the same time should they delete (by standing on 2 blocks). If you place them in the vertical level's top-left sub-screen boundary. So here is a fix for the \$99/\$9B fix:

Code
```;this routine fixes vertical level block-positioning issues after you change map16.
LDA \$5B				;\Check if vertical level = true
AND #\$01			;|
BEQ +				;/
LDA \$99				;\Prevent strange behavor on top-left subscreen of vertical level.
BNE ++				;|(such as interact with the wrong blocks; 2 blocks at same time)
LDA \$9B				;|
BNE ++				;|
BRA +				;/
++
PHY
LDA \$99				;\Fix the \$99 and \$9B from glitching up if placed
LDY \$9B				;|other than top-left subscreen boundaries of vertical
STY \$99				;|levels!!!!! (barrowed from the map16 change routine of GPS).
STA \$9B				;|(this switch values \$99 <-> \$9B, since the subscreen boundaries are sideways).
PLY
+					;/
RTL```

Use this after every time you use the map16 change or the erase block.

--------------------
Give thanks to RPG hacker for working on Asar.
Sprite template

--------------------
Give thanks to RPG hacker for working on Asar.
Just like custom sprites and blocks, custom objects are also possible with this patch (come to think of it, it might not be a bad idea to update that with some additional routines and stuff), but not many people actually seem to use custom objects, especially non-extended ones. I figure that part of that is Lunar Magic not displaying them properly, but it probably doesn't help that there aren't a bunch of pre-existing resources for them like there are for sprites and blocks. So here are a few base codes that can be used for your own custom objects. They do take a slight bit of ASM knowledge, but nothing too complicated.

Code
```Objects16x16:
ASL
TAX
LDY \$57
LDA.w Obj16x16Tiles,x
STA [\$6B],y
LDA.w Obj16x16Tiles+1,x
STA [\$6E],y
RTS

Objects16x32:
ASL #2
TAX
LDY \$57
LDA.w Obj16x32Tiles,x
STA [\$6B],y
LDA.w Obj16x32Tiles+1,x
STA [\$6E],y
INX : INX
JSR ShiftObjDown
LDA.w Obj16x32Tiles,x
STA [\$6B],y
LDA.w Obj16x32Tiles+1,x
STA [\$6E],y
RTS

Objects32x16:
ASL #2
TAX
LDY \$57
LDA.w Obj32x16Tiles,x
STA [\$6B],y
LDA.w Obj32x16Tiles+1,x
STA [\$6E],y
INX : INX
JSR ShiftObjRight
LDA.w Obj32x16Tiles,x
STA [\$6B],y
LDA.w Obj32x16Tiles+1,x
STA [\$6E],y
RTS

Objects32x32:
ASL #3
TAX
JSR BackUpPtrs
LDY \$57
LDA.w Obj32x32Tiles,x
STA [\$6B],y
LDA.w Obj32x32Tiles+1,x
STA [\$6E],y
INX : INX
JSR ShiftObjRight
LDA.w Obj32x32Tiles,x
STA [\$6B],y
LDA.w Obj32x32Tiles+1,x
STA [\$6E],y
JSR RestorePtrs
JSR ShiftObjDown
INX : INX
LDA.w Obj32x32Tiles,x
STA [\$6B],y
LDA.w Obj32x32Tiles+1,x
STA [\$6E],y
INX : INX
JSR ShiftObjRight
LDA.w Obj32x32Tiles,x
STA [\$6B],y
LDA.w Obj32x32Tiles+1,x
STA [\$6E],y
RTS

Obj16x16Tiles:
;	dw \$0000	; index 00
;...

Obj16x32Tiles:
;	dw \$0000,\$0000	; index 00
;...

Obj32x16Tiles:
;	dw \$0000,\$0000	; index 00
;...

Obj32x32Tiles:
;	dw \$0000,\$0000,\$0000,\$0000	; index 00
;...```

These routines will make an extended object consisting of a 1x1, 1x2, 2x1, or 2x2 array of blocks. The tables should consist of one 16-bit value per block for each entry, as you see here. Load the index you want into A before calling the routine. (These may seem pointless given that Direct Map16 exists, but keep in mind that you can also have them load variable values depending on a specified factor, such as item memory or switch palace flags.) Note that it is currently not possible to go beyond index \$7F for the 16x16, \$3F for the 16x32 and 32x16, and \$1F for the 32x32 ones, because the index to the tables is only 8-bit. If I end up needing more for my own objects, I will probably add 16-bit indexing to the routines and add them to this post.

Code
```SquareObjects:
REP #\$20					;
AND.w #\$00FF				;
ORA #\$0900				;
STA \$4202				;
JSR .Return				;
LDA \$4216				;
STA \$0C					;
SEP #\$20					;
JSR StoreNybbles			;
LDY \$57					;
LDA \$08					;
STA \$00					;
STA \$02					;
LDA \$09					;
STA \$01					;
JSR BackUpPtrs				;
.StartObjLoop					;
REP #\$10					;
LDX \$0C					;
LDA \$01					;
CMP \$09					;
BEQ .NoInc1				;
INX #3					;
CMP #\$00				;
BNE .NoInc1				;
INX #3					;
.NoInc1						;
LDA \$02					;
CMP \$08					;
BEQ .SetTileIndex			;
INX						;
CMP #\$00				;
BNE .SetTileIndex			;
INX						;
.SetTileIndex					;
REP #\$20					;
TXA						;
ASL						;
TAX						;
LDA.w SquareObjTiles,x		;
SEP #\$30					;
STA [\$6B],y				;
XBA						;
STA [\$6E],y				;
JSR ShiftObjRight			; shift the tile position right one tile
.DecAndLoop					;
DEC \$02					; if there are more tiles to draw on this line...
BPL .StartObjLoop			; loop the routine
JSR RestorePtrs			; if not, restore the base tile position...
JSR ShiftObjDown			; and move on to the next line
LDA \$00					;
STA \$02					; also reset the X position counter
DEC \$01					; decrement the Y position (line) counter
BMI .EndObjLoop			; if still positive...
JMP .StartObjLoop			; loop the routine
.EndObjLoop					;
.Return						;
RTS						;

SquareObjects2:
REP #\$20					;
AND.w #\$00FF				;
ORA #\$0900				;
STA \$4202				;
JSR .Return				;
LDA \$4216				;
STA \$0C					;
SEP #\$20					;
JSR StoreNybbles			;
LDY \$57					;
LDA \$08					;
STA \$00					;
STA \$02					;
LDA \$09					;
STA \$01					;
JSR BackUpPtrs				;
.StartObjLoop					;
REP #\$10					;
LDX \$0C					;
LDA \$01					;
CMP \$09					;
BEQ .NoInc1				;
INX #3					;
CMP #\$00				;
BNE .NoInc1				;
INX #3					;
.NoInc1						;
LDA \$02					;
CMP \$08					;
BEQ .SetTileIndex			;
INX						;
CMP #\$00				;
BNE .SetTileIndex			;
INX						;
.SetTileIndex					;
LDA [\$6E],y				;
XBA						;
LDA [\$6B],y				;
REP #\$20					;
CLC						;
ADC #\$7FDA				; #\$0025 + #\$7FDA = #\$7FFF
REP #\$41					; make sure V and C are clear
ADC #\$0001				; this should set overflow if and only if the tile number was 25
TXA						;
ASL						;
TAX						;
LDA.w SquareObjTiles2A,x	;
BVS .NoAlt				;
LDA.w SquareObjTiles2B,x	;
.NoAlt						;
SEP #\$30					;
STA [\$6B],y				;
XBA						;
STA [\$6E],y				;
JSR ShiftObjRight			; shift the tile position right one tile
.DecAndLoop					;
DEC \$02					; if there are more tiles to draw on this line...
BPL .StartObjLoop			; loop the routine
JSR RestorePtrs			; if not, restore the base tile position...
JSR ShiftObjDown			; and move on to the next line
LDA \$00					;
STA \$02					; also reset the X position counter
DEC \$01					; decrement the Y position (line) counter
BMI .EndObjLoop			; if still positive...
JMP .StartObjLoop			; loop the routine
.EndObjLoop					;
.Return						;
RTS						;

SquareObjTiles:
;	dw \$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000	; index 00

SquareObjTiles2A:
;	dw \$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000	; index 00
SquareObjTiles2B:
;	dw \$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000,\$0000	; index 00```

These are for normal objects that have an array of 9 tiles, with the middle ones stretchable (think the SMB3 metal blocks, or any 4-sided ground object). The block number tables use 9 values in the order you'd expect (top-left corner, top-middle, top-right, middle-left edge, middle, middle-right, bottom-left, bottom-middle, bottom-right). They can also be used for ledges if you set the middle and bottom rows to the same numbers. There are two routines here, and the second one is for objects that change when placed over something else, as ledges do (with the corners becoming filled in). For that one, the first table is for when that part of the object is over a blank tile, and the second table is for when it is over a non-blank tile. Like the previous set, the value in A before calling the routine determines which list of blocks will be used, though it can go all the way up to \$FF this time since the index becomes 16-bit. You should also JSR to the "StoreNybbles" subroutine before using these.

Code
```ClusterExObjRt:
TAY
LDA ClusterExObjSize,y
PHA
AND #\$0F
STA \$00
STA \$02
PLA
LSR #4
STA \$01
TYA
ASL
TAY
REP #\$20
LDA ClusterExObjPtrs,y
STA \$0A
SEP #\$20
LDY \$57
JSR BackUpPtrs
.Loop
REP #\$20
LDA (\$0A)
CMP #\$FFFF
SEP #\$20
BEQ .SkipTile
STA [\$6B],y
XBA
STA [\$6E],y
.SkipTile
JSR ShiftObjRight
REP #\$20
INC \$0A
INC \$0A
SEP #\$20
DEC \$02
BPL .Loop
JSR RestorePtrs
JSR ShiftObjDown
LDA \$00
STA \$02
DEC \$01
BPL .Loop
RTS

ClusterExObjSize:
;	db \$42

; pointers to the tilemaps of extended objects consisting of a large group of tiles
ClusterExObjPtrs:
;	dw TileArray00

TileArray00:
;	dw \$0000,\$0000,\$0000
;	dw \$0000,\$0000,\$0000
;	dw \$0000,\$0000,\$0000
;	dw \$0000,\$0000,\$0000
;	dw \$0000,\$0000,\$0000```

This is for non-stretchable objects of variable dimensions. (This is a simplified version; the one I use has a couple extra behavior checks that I felt most people might not need and might simply get tripped up by.) The input is the same as it is for the others, just the index you want to use. The tables are a bit different here. The first is for the size, first digit for Y and second for X (minus 1, so \$11 would create a 2x2 object); the second is a list of pointers to the block data; and the third is the block data itself. (Example data is shown.) The block data consists of Map16 numbers as usual, but putting \$FFFF in for any number will skip that particular block. (This is not the same as drawing an empty block, or Map16 tile 25, which would overwrite anything already placed in that area by another object with empty space.) You can use this subroutine for things like the large bushes.
Updated sa-1/superfx check:
Code
```	!dp = \$0000
!sa1 = 0
!gsu = 0

sfxrom
!dp = \$6000
!gsu = 1
sa1rom
!dp = \$3000
!sa1 = 1
endif```

In case if users don't have to go to the patch section.

--------------------
Give thanks to RPG hacker for working on Asar.
sfxrom is broken. Stick to sa1rom.

--------------------
I'm sure I'll find it
Wasn't sfxrom fixed with Raiden's update?
I use the latest version and I'm pretty sure it still doesn't work.

--------------------
I'm sure I'll find it
You are using the asar version in the waiting tools, right?

--------------------
Give thanks to RPG hacker for working on Asar.
You shouldn't build any standards requiring "unverified" tools.

--------------------
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
Removing the RNG from Footballs:

Code
```!MiscTable = \$1594

org \$03800E
db \$A0,\$C0,\$D0,\$D0	;data table for the bounce speed of footballs

org \$03805C

autoclean JSL NewFootBall

freecode

NewFootBall:
LDA !MiscTable,x
BNE IsSet
LDA #\$A6
IsSet:
ROR
STA !MiscTable,x
RTL
```
Insertion sort algorithm: (sorts in increasing order, unsigned)

8-bit:
Code
```!Freeram_BufferSort = \$7FA000
;^Format: nnnnnnnn (1 byte each). Number of items equal to how
;many bytes consume this freeram.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Input:
;; *!Freeram_BufferSort: Write any numbers (1-byte each) here.
;;
;; *\$00: Number of items to sort.
;;
;;Output:
;;
;;Destroyed values:
;; *\$01: A memory index position needed so when moving multiple
;;   items foward, does continue back after placing the item-in-hand back.
;; *\$02: A holder used to place the number at the correct spot.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

InsertionSort:
PHX
LDX #\$01			;>Start at the 2nd item ("grabber")
STX \$01				;>Start memory position

.Loop
LDA !Freeram_BufferSort,x	;\Grab value to compare (about to drop it).
STA \$02				;/

..ShiftElementAgain
CPX #\$00			;\Prevent searching and dropping value in invalid indexes.
BEQ ..DropValueToFirst		;/This also means that the item grabbed is the smallest number possible.
LDA \$02				;>This is so that when the loops comes around, still compares with the number grabbed.
DEX				;>Check previous to find correct spot.
CMP !Freeram_BufferSort,x	;>Compare with previous value
BCC ..MovePrev			;>If grabbed value is smaller, move larger number over and execute move item loop
BRA ..DropValue			;>If not "put it back", needed if it finally finds the correct place to drop.

..MovePrev
INX				;>Move previous item index into a space where the item is "grabbed"
STA !Freeram_BufferSort,x	;>Move item 1 space foward.
DEX				;>Place index back (index doesn't move/change after this).
BRA ..ShiftElementAgain		;>Loop again to see if needed to shift again or drop.

..DropValue
INX				;>go back and drop larger index positioned after the smaller number (place 2 after 1).

..DropValueToFirst
LDA \$02
STA !Freeram_BufferSort,x

..CheckNextValue
INC \$01				;\Continue where left off since it started grabbing a number
LDX \$01				;/
CPX \$00				;\Loop until all numbers sorted
BCC .Loop			;/

.SuboutineDone
PLX
RTL```

16-bit:
Code
```!Freeram_BufferSort = \$7FA000
;^Format: nnnnnnnn NNNNNNNN (each item is 2 bytes). Number of
;items *2 equal to how many bytes consume this freeram. Should
;not be higher than 128.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Input:
;; *!Freeram_BufferSort: Write any numbers (2-bytes each) here.
;;
;; *\$00: Number of items *2 to sort (4 items, you would write 8). Does not
;;  work if >128 (#\$80), since index is 8-bit.
;;
;;Output:
;;
;;Destroyed values:
;; *\$01: A memory index position needed so when moving multiple
;;   items foward, does continue back after placing the item-in-hand back.
;; *\$02-\$03: A holder used to place the number at the correct spot.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

InsertionSort:
PHX
REP #\$20
LDX #\$02			;>Start at the 2nd item ("grabber")
STX \$01				;>Start memory position

.Loop
LDA !Freeram_BufferSort,x	;\Grab value to compare (about to drop it).
STA \$02				;/

..ShiftElementAgain
CPX #\$00			;\Prevent searching and dropping value in invalid indexes.
BEQ ..DropValueToFirst		;/This also means that the item grabbed is the smallest number possible.
LDA \$02				;>This is so that when the loops comes around, still compares with the number grabbed.
DEX #2				;>Check previous to find correct spot.
CMP !Freeram_BufferSort,x	;>Compare with previous value
BCC ..MovePrev			;>If grabbed value is smaller, move larger number over and execute move item loop
BRA ..DropValue			;>If not "put it back", needed if it finally finds the correct place to drop.

..MovePrev
INX #2				;>Move previous item index into a space where the item is "grabbed"
STA !Freeram_BufferSort,x	;>Move item 1 space foward.
DEX #2				;>Place index back (index doesn't move/change after this).
BRA ..ShiftElementAgain		;>Loop again to see if needed to shift again or drop.

..DropValue
INX #2				;>go back and drop larger index positioned after the smaller number (place 2 after 1).

..DropValueToFirst
LDA \$02
STA !Freeram_BufferSort,x

..CheckNextValue
SEP #\$20			;>8-bit mode
INC \$01				;\Continue where left off since it started grabbing a number.
INC \$01				;/(INC \$xx twice takes less space than having LDA and STA around it).
REP #\$20			;>16-bit mode
LDX \$01				;>set index to where left off.
CPX \$00				;\Loop until all numbers sorted
BCC .Loop			;/

.SuboutineDone
SEP #\$20
PLX
RTL```

Not really useful for smw, but for advanced ASM'ers that have a “record” gimmick, such as showing “top 3 quickest level completion” (simply by comparing minutes, then seconds, and finally frames). Make sure you edit to not only sort the numbers in the tables themselves, but also the “id” (in a new table) of the item everytime there is LDA and STA for !Freeram_BufferSort (so if you're going to make a high score mechanic, that not only stores the score, but also things like names of something (3000 GreenHammerBro), you would need to move the ID (GreenHammerBro) and not just the score number), otherwise you end up mixing up the score number and the ID. Of course if there are 3+ things per item (3000 GreenHammerBro 50), the ID can be used to store multiple items (the “GreenHammerBro” and the “50&rdquo to be moved). This will make it so that it will move all the items together.

--------------------
Give thanks to RPG hacker for working on Asar.
Originally posted by MarioE
Using an inlined reciprocal square root routine, I've created a pretty accurate aiming routine. Link

In order to use it, set \$00 to be the 16-bit value (shooter_x - target_x), set \$02 to be the 16-bit value (shooter_y - target_y), and set A to be the 8-bit projectile speed. It will return the projectile's X speed in \$00 and the projectile's Y speed in \$02. Note that distances over \$0100 pixels are not allowed.

Explanation: Suppose one fired the projectile with X speed dx, and Y speed dy. Then its speed would be sqrt(dx2+dy2). Thus, we can adjust its speed by multiplying by speed / sqrt(dx2+dy2). This routine calculates the reciprocal 1 / sqrt(dx2+dy2), multiplies by speed, then multiplies by either dx or dy.

This is why you should not use temporally storage to share your files, it will not last for long term (error 404)

Thank god I use this subroutine on one of my stuff.

Code
```;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Aiming routine, by MarioE.
;Input:
;\$00 = (shooter_x - target_x), 16-bit
;\$02 = (shooter_y - target_y), 16-bit
;A = projectile speed
;Output:
;\$00 = X speed
;\$02 = Y speed
;NOTE: distance more than \$0100 (256 in decimal) will glitch, unless you divide them by
;the same number (like both by 4) to go under 256 and it still works.
;
;MarioE's explanation: Suppose one fired the projectile with X speed dx, and Y speed dy.
;Then its speed would be sqrt(dx2+dy2). Thus, we can adjust its speed by multiplying by
;speed / sqrt(dx2+dy2). This routine calculates the reciprocal 1 / sqrt(dx2+dy2),
;multiplies by speed, then multiplies by either dx or dy.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
recip_sqrt_lookup:
dw \$0000,\$FFFF,\$B505,\$93CD,\$8000,\$727D,\$6883,\$60C2
dw \$5A82,\$5555,\$50F4,\$4D30,\$49E7,\$4700,\$446B,\$4219
dw \$4000,\$3E17,\$3C57,\$3ABB,\$393E,\$37DD,\$3694,\$3561
dw \$3441,\$3333,\$3235,\$3144,\$3061,\$2F8A,\$2EBD,\$2DFB
dw \$2D41,\$2C90,\$2BE7,\$2B46,\$2AAB,\$2A16,\$2987,\$28FE
dw \$287A,\$27FB,\$2780,\$270A,\$2698,\$262A,\$25BF,\$2557
dw \$24F3,\$2492,\$2434,\$23D9,\$2380,\$232A,\$22D6,\$2285
dw \$2236,\$21E8,\$219D,\$2154,\$210D,\$20C7,\$2083,\$2041
dw \$2000,\$1FC1,\$1F83,\$1F46,\$1F0B,\$1ED2,\$1E99,\$1E62
dw \$1E2B,\$1DF6,\$1DC2,\$1D8F,\$1D5D,\$1D2D,\$1CFC,\$1CCD
dw \$1C9F,\$1C72,\$1C45,\$1C1A,\$1BEF,\$1BC4,\$1B9B,\$1B72
dw \$1A21,\$19FE,\$19DC,\$19BB,\$199A,\$1979,\$1959,\$1939
dw \$191A,\$18FC,\$18DD,\$18C0,\$18A2,\$1885,\$1869,\$184C
dw \$1831,\$1815,\$17FA,\$17DF,\$17C5,\$17AB,\$1791,\$1778
dw \$175F,\$1746,\$172D,\$1715,\$16FD,\$16E6,\$16CE,\$16B7
dw \$16A1,\$168A,\$1674,\$165E,\$1648,\$1633,\$161D,\$1608
dw \$15F4,\$15DF,\$15CB,\$15B7,\$15A3,\$158F,\$157C,\$1568
dw \$1555,\$1542,\$1530,\$151D,\$150B,\$14F9,\$14E7,\$14D5
dw \$14C4,\$14B2,\$14A1,\$1490,\$147F,\$146E,\$145E,\$144D
dw \$143D,\$142D,\$141D,\$140D,\$13FE,\$13EE,\$13DF,\$13CF
dw \$13C0,\$13B1,\$13A2,\$1394,\$1385,\$1377,\$1368,\$135A
dw \$134C,\$133E,\$1330,\$1322,\$1315,\$1307,\$12FA,\$12ED
dw \$12DF,\$12D2,\$12C5,\$12B8,\$12AC,\$129F,\$1292,\$1286
dw \$127A,\$126D,\$1261,\$1255,\$1249,\$123D,\$1231,\$1226
dw \$121A,\$120F,\$1203,\$11F8,\$11EC,\$11E1,\$11D6,\$11CB
dw \$11C0,\$11B5,\$11AA,\$11A0,\$1195,\$118A,\$1180,\$1176
dw \$116B,\$1161,\$1157,\$114D,\$1142,\$1138,\$112E,\$1125
dw \$111B,\$1111,\$1107,\$10FE,\$10F4,\$10EB,\$10E1,\$10D8
dw \$10CF,\$10C5,\$10BC,\$10B3,\$10AA,\$10A1,\$1098,\$108F
dw \$1086,\$107E,\$1075,\$106C,\$1064,\$105B,\$1052,\$104A
dw \$1042,\$1039,\$1031,\$1029,\$1020,\$1018,\$1010,\$1008

aiming:		PHX
PHY
PHP
SEP #\$30
STA \$0F

LDX #\$00
REP #\$20
LDA \$00
BPL .pos_dx
EOR #\$FFFF
INC
INX
INX
STA \$00
.pos_dx	SEP #\$20
STA \$4202
STA \$4203

NOP
NOP
NOP
REP #\$20
LDA \$4216
STA \$04
LDA \$02
BPL .pos_dy
EOR #\$FFFF
INC
INX
STA \$02
.pos_dy	SEP #\$20
STA \$4202
STA \$4203
STX \$0E

REP #\$30
LDA \$04
CLC
LDY #\$0000
BCC .loop
INY
ROR
LSR
.loop	CMP #\$0100
BCC +
INY
LSR
LSR
BRA .loop
+	CLC
ASL
TAX
LDA recip_sqrt_lookup,x
-	DEY
BMI +
LSR
BRA -
+	SEP #\$30

STA \$4202
LDA \$0F
STA \$4203
NOP
STZ \$05
STZ \$07
LDA \$4217
STA \$04
XBA
STA \$4202
LDA \$0F
STA \$4203

REP #\$20
LDA \$04
CLC
STA \$04
SEP #\$20

LDX #\$02
-	LDA \$04
STA \$4202
LDA \$00,x
STA \$4203

NOP
NOP
NOP
NOP

LDA \$4217
STA \$06
LDA \$05
STA \$4202
LDA \$00,x
STA \$4203

REP #\$20
LDA \$06
CLC
SEP #\$20

LSR \$0E
BCS +
EOR #\$FF
INC
+	STA \$00,x
DEX
DEX
BPL -

PLP
PLY
PLX
RTL```

There should be a rule against uploading it in places that it doesn't guarantee it would stay there, otherwise stuff would "rot" and nobody could find it.

Edit: unlimited distance.

--------------------
Give thanks to RPG hacker for working on Asar.
This is updated to be more valid even to the human eye, No freespace required!

This should be considered the final edition of this patch, unless someone finds a problem, of which there should be none.

Code
```;Attributes for the Misc. Switch Palace Sprites
;By Hamtaro126, No Credit necessary!

org \$05B29B
;;;;;;;;;;;;;;;;;;;;;;
;Tiles and Attributes;
;;;;;;;;;;;;;;;;;;;;;;
dw \$35A7,\$75A7,\$35B7,\$75B7 ;/ Yellow Exclamation Block
dw \$37BD,\$77BD,\$B7BD,\$F7BD ;\ Blue Dotted Line Block
dw \$37A7,\$77A7,\$37B7,\$77B7 ;/ Blue Exclamation Block
dw \$39A7,\$79A7,\$39B7,\$79B7 ;/ Red Exclamation Block
dw \$3BBD,\$7BBD,\$BBBD,\$FBBD ;\ Green Dotted Line Block
dw \$3BA7,\$7BA7,\$3BB7,\$7BB7 ;/ Green Exclamation Block

org \$02CD55
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Flat Palace Switch colors (Green, Yellow, Blue, Red);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
db \$0A,\$04,\$06,\$08

org \$02CD4D
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;The Bottom of the Flat Palace Switch, Use it if changing the palette and map16;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
db \$31,\$31,\$71,\$71,\$31,\$31,\$71,\$71
```
 Pages: 1 2 3 4 5 6 7 8
Forum Index - SMW Hacking - SMW Hacking Help - ASM & Related Topics - Advanced Documentation and ASM Code Library

The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.