Banner
Views: 773,052,379
Time:
8 users online: bandicoot, GFL2018HACKS, hash, Magmatic, Nowieso, placeholdertest, UltiMario,  xHF01x - Guests: 66 - Bots: 170Users: 40,602 (1,831 active)
Latest: Overcrow
Tip: If you're using the wall-running purple triangles in your hack, remember to add tile 1EB (or a tile that acts like tile 1EB) underneath it. Extended object 44/45 will include this tile for you.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 »
Here is the explanation how this works when you use JSL -> RTS:

Code
	PHK                       ;\This will push the 24-bit address location
	PEA.w .jslrtsreturn-1     ;/after the JML (below) into the stack*
	PEA $yyyy-1               ;>This modifies the RTS in the pointed routine (below) to jump to an RTL in same bank.*
                                  ;^This RTL then pulls the stack (which is the 24-bit address) to jump to a location after the JML
	JML $xxxxxx               ;>The desired routine that ends with RTS

	.jslrtsreturn

*Means that when the PC (program counter) "returns" (weather RTS or RTL), it pulls the stack + 1. I've learned it from Ersanio's ASM tutorial (not the SMW version).
Originally posted by Ersanio
About JSR and JSL, and RTS and RTL:
Imagine that there is a JSR opcode located at $8000, and there is an LDA at $8003, and RTS at $B000. A JSR instruction is 3 bytes long (JSR $xxxx). So we have this:
Code
$8000 JSR $B000
$8003 LDA #$01
…
$B000 RTS

Now, what JSR does is, pushing the next instruction’s location - $0001 onto the stack. This means, that the value $8002 is pushed on the stack. Then JSR jumps to the specified address. What RTS does, is pulling that $8002 from the stack and adding $0001 to it, and storing it into the program counter register, causing the program to jump back to the instruction after that JSR.
JSL and RTL work the same way, except these push and pull 24-bit addresses. JSL pushes the long address - 1 onto the stack and jumps to the specified address, and RTL pulls the long address +1 onto the stack and jump to it.


--------------------
Give thanks to RPG hacker for working on Asar.
Count how many bits are set in a specified range of address:
Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Counts how many bits are set in a specified address range.
;
;Input:
; $00-$01 = the starting address to count bits, low endian.
;  ($AABB -> $BB $AA)
;
; $02-$03 = the ending address to count bits, same format
;  as above.
;
; $04 = the bank byte of the address. The range of bytes to
;  check must be in the same bank. if not, try calling this
;  subroutine twice or more but with
;  "JSL ContinueCountBits" instead.
;
;Output:
;*$05-$06 = the number of bits being set.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CountSetBitsAtStart:
	STZ $05			;\Reset counter
	STZ $06			;/
ContinueCountBits:
	PHB			;>Just in case
	LDA $04			;\Adjust bank.
	PHA			;|
	PLB			;/

	.LoopBytes
	LDY #$07		;>Check each bit in a byte
	LDA ($00)		;>Load address stored in $00, A should have a value inside the pointed value

	..LoopThroughBits
	LSR			;>Shift bit right
	BCC ...NextBit		;>If bit moved into carry is clear, don't count.
	REP #$20		;\Increment bit counter
	INC $05			;|
	SEP #$20		;/

	...NextBit
	DEY			;>Next bit
	BPL ..LoopThroughBits	;>Keep until full byte has been checked.

	.NextByte
	REP #$20		;>16bit A
	INC $00			;>Next address to read
	LDA $00			;>This is so that the branches below works.
	CMP $02			;>The last byte
	SEP #$20		;>8bit A
	BEQ .LoopBytes		;\If not past the final byte, loop
	BCC .LoopBytes		;/
	PLB			;>Restore bank
	RTL

This is useful for hacks that have things stored in as bits and you want to count how many. For example, counting how many star coins collected total without having a separate RAM that increments each time you collect (since how levels remember that each star coins being collected and was stored as bits).
Here is how to use:
Code
;Example, checks how many set bits from $7E0060 to $7E0063
	REP #$20
	LDA #$0060	;>Start Address
	STA $00
	LDA #$0063	;>End address
	STA $02
	SEP #$20
	
	LDA #$7E	;>Bank address
	STA $04
	JSL CountSetBits
	RTL

Be careful not to have a possibility of having more than 65535 bits set, as the counter is 16-bit. Here is an example on how to call.

--------------------
Give thanks to RPG hacker for working on Asar.
Honestly think you'd have an easier time passing the length instead of the end address. Like:
(untested code written in 5 minutes, don't kill me if it's actually nonsense.)
Code
;$00 = 3 byte pointer
;A   = length - 1
;X   = 16 bit output counter

Count:
	PHP
	REP #$30	; all 16 bit.
	TAY		; length in Y
	SEP #$20	; A back to 8 bit
	LDX #$0000	; reset counter

	PHB
	LDA $02
	PHA : PLB

.loop
	LDA ($0000),y	; load value
	BEQ +		; skip altogether if already empty
-	LSR		; shift LSB into carry
	BCC ++		; skip increment if carry clear
	INX		; increment
++	CMP #$00	; \ end once A is 0
	BNE -		; /

+	DEY		; more to go?
	BPL .loop

	PLB
	PLP
	RTL


Alternatively you could make Y the input for the length and not bother with the TAY thing at all.
Plus, I'm not too sure if TAY doesn't transfer all 16 bits regardless of process flag, so you could potentially skip the REP #$30 : SEP #$20 with just a REP #$10

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


Originally posted by JackTheSpades
(untested code written in 5 minutes, don't kill me if it's actually nonsense.)

(it's a bit nonsense)
LDA (addr),y doesn't exist, for one thing

Something like this would probably work instead:

Code
; Input:
; $00 = 24-bit pointer to start address.
;   A = number of bytes to count (16-bit)

Count:
	PHX
	PHY
	PHP

	REP #$10
	TAY
	SEP #$20
	LDX #$0000	; reset counter

.loop
	LDA [$00],y	; load value
	BEQ ++		; skip altogether if already empty
-	LSR		; shift LSB into carry
	BCC +		; skip increment if carry clear
	INX		; increment
+	CMP #$00	; \ end once A is 0
	BNE -		; /

++	DEY		; more to go?
	BPL .loop

	PLP
	PLY
	PLX
	RTL


Professional frame-by-frame time wizard. YouTube - Twitter - SMW Glitch List - SMW Randomizer
When are we need that code?
I'm created many sprites, blocks, and patches so far, but I didn't need that.

Stupid solution (untested)
Code
; Input:
; $00 = 24-bit pointer to start address.
;   A = number of bytes to count (16-bit)
;
; Output:
; $03-$04 = number of bits being set

Count:	PHX
	PHY
	PHP
	
	REP #$31
	TAY
	STZ $03
	
-	LDA [$00],y
	AND.w #$00FF
	TAX
	LDA.l .BitTable,x
	AND.w #$00FF
	ADC $03
	STA $03
	DEY
	BPL -
	
	PLP
	PLY
	PLX
	RTL
	
.BitTable
db $00,$01,$01,$02,$01,$02,$02,$03,$01,$02,$02,$03,$02,$03,$03,$04
db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05
db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05
db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06
db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05
db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06
db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06
db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07
db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05
db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06
db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06
db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07
db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06
db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07
db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07
db $04,$05,$05,$06,$05,$06,$06,$07,$05,$06,$06,$07,$06,$07,$07,$08
Simple increment/decrement counter effect. Useful if you want to show to the player that something has decreased or increased.

Code
!RAM_Record = $xxxx	;>The value shown that slowly increases/decreases
!RAM_RealVal = $yyyy	;>The real value that isn't shown, but shown "slowly follows" this value.

	LDA !RAM_Record
	CMP !RAM_RealVal
	BEQ .Done
	BMI .Increment			;>Feel free to change to BCC if unsigned.

	.Decrement
	LDA $13				;>Frame counter
	AND #$03			;>choose any value that is base2 minus 1 (modulo)
	BNE .Done			;>If any remainder bits set, don't change.
	LDA !RAM_Record
	DEC 
	STA !RAM_Record
	BRA .Done

	.Increment
	LDA $13				;>Frame counter
	AND #$03			;>choose any value that is base2 minus 1 (modulo)
	BNE ..Done			;>If any remainder bits set, don't change.
	LDA !RAM_Record
	INC 
	STA !RAM_Record

	.Done
	[...]

16-bit version:
Code
!RAM_Record = $xxxx	;>The value shown that slowly increases/decreases
!RAM_RealVal = $yyyy	;>The real value that isn't shown, but shown "slowly follows" this value.
	REP #$20
	LDA !RAM_Record
	CMP !RAM_RealVal
	SEP #$20
	BEQ .Done
	BMI .Increment			;>Feel free to change to BCC if unsigned.

	.Decrement
	LDA $13				;>Frame counter
	AND #$03			;>choose any value that is base2 minus 1 (modulo)
	BNE .Done			;>If any remainder bits set, don't change.
	REP #$20
	LDA !RAM_Record
	DEC 
	STA !RAM_Record
	SEP #$20
	BRA .Done

	.Increment
	LDA $13				;>Frame counter
	AND #$03			;>choose any value that is base2 minus 1 (modulo)
	BNE ..Done			;>If any remainder bits set, don't change.
	REP #$20
	LDA !RAM_Record
	INC 
	STA !RAM_Record
	SEP #$20

	.Done
	[...]


--------------------
Give thanks to RPG hacker for working on Asar.
Originally posted by Akaginite
I had implemented another RNG routine at about 6 years ago.

Code
; 8bit Twisted-GFSR generator
; Period : 2^32-1
; 4 Bytes used

!Random =	$148B

TGFSR:		PHY
		LDA.w !Random+$01
		LSR A
		BCS +
		EOR #$95		; maximum tap values: 0x8E,0x95,0x9F,0xA6,0xB2
+		EOR.w !Random+$02
		EOR.w !Random+$00
		LDY.w !Random+$02
		STA.w !Random+$02
		LDA.w !Random+$03
		STY.w !Random+$03
		LDY.w !Random+$00
		STA.w !Random+$00
		STY.w !Random+$01
		PLY
		RTL

8bit Mersenne-Twister generator
I think this RNG has over-engineering for use in SMW.


Code
!MT_N =		160
!MT_M =		31
!MT_MATRIX =	$B2


What does those mean?

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


Originally posted by GreenHammerBro
Code
!MT_N =		160
!MT_M =		31
!MT_MATRIX =	$B2


What does those mean?

Those are just some parameters for the Merseene Twister's algorithm. N is the degree of recurrence, which can be calculated as desired Mersenne prime (1279) divided by the number of bits in each RNG value (8), rounded up; this value plus 1 also indicates how many values need to be in the SeedData table. M is somewhat freely chosen, just with M < N. Lastly, the MATRIX value is a series of bitwise matrix coefficents, which has a formula that I can't really explain briefly (Wikipedia kinda does).

Professional frame-by-frame time wizard. YouTube - Twitter - SMW Glitch List - SMW Randomizer
SA-1 Unsigned 16bit * 16bit multiplication routine

SA-1's arithmetic operations are calculated by signed.
for that reason, this routine doing signed to unsigned conversion.

Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 16bit * 16bit Multiplication SA-1 version
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Argusment
; $00-$01 : Multiplicand
; $02-$03 : Multiplier
; Return values
; $04-$07 : Product
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MathMul16_16:	STZ $2250
		REP #$20
		LDA $00
		STA $2251
		ASL A
		LDA $02
		STA $2253
		BCS +
		LDA.w #$0000
+		BIT $02
		BPL +
		CLC
		ADC $00
+		CLC
		ADC $2308
		STA $06
		LDA $2306
		STA $04
		SEP #$20
		RTS
This is interesting. But don't the result will come messed up if you don't remove the sign bit in $2251 bit 15 and $2253 bit 15?... How you did the "to unsigned" logic there?

That routine reminds me of... I never managed to make a 32 bit by 16 bit divider (or even 24 bit by 16 bit) using 16 bit by 16 bit divider. But that probably is not possible unfortunately.

--------------------
GitHub - Twitter - YouTube - Blog - SnesLab Discord
Originally posted by Vitor Vilela
This is interesting. But don't the result will come messed up if you don't remove the sign bit in $2251 bit 15 and $2253 bit 15?... How you did the "to unsigned" logic there?

That routine reminds me of... I never managed to make a 32 bit by 16 bit divider (or even 24 bit by 16 bit) using 16 bit by 16 bit divider. But that probably is not possible unfortunately.


this code is implemented by my experience, but I can't prove mathematically why it works fine. I'm silly.

verification of calculate:
Code
1) 0x004C * 0x9A63
Signed   : 0xFFE1 D564
Unsigned : 0x002D D564
Signed to Unsigned : 0xFFE1 D564 + 0x004C 0000 -> 0x002D D564

2) 0x8765 * 0x4321
Signed   : 0xE05F E305
Unsigned : 0x2380 E305
Signed to Unsigned : 0xE05F E305 + 0x4321 0000 -> 0x2380 E305

3) 0x8000 * 0xABCD
Signed   : 0x2A19 8000
Unsigned : 0x55E6 8000
Signed to Unsigned : 0x2A19 8000 + 0x8000 0000 + 0xABCD 0000 -> 55E6 8000
I have made a test program that did all multiplication possibles and indeed it works perfectly. This is pretty amazing!

I really wanted if it was possible to do an unsigned 16 bit division, but then the division does not have any similar property.

The divisor in SA-1 is unsigned, which is less bad (or more bad, I don't know). It's a quite bizarre to SA-1 division be signed by unsigned but lol.

Excellent work for finding this, though.

--------------------
GitHub - Twitter - YouTube - Blog - SnesLab Discord
Opcode database.

--------------------
Give thanks to RPG hacker for working on Asar.
Update that comes along with my 4-5 hex-> dec subroutine: the leading zeroes remover.

--------------------
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.

erik edit: fixed link because dropbox
added the sa-1 compatible variant (requires a !SA1 detection if you're using spritetool)


optimized for cycle count and tweaked to unlimited distance.

Aligned number display (the “X” symbol was meant to be the “/” graphic symbol, but SMW does not have that):


This code displays numbers left or right-aligned with leading zeroes suppressed (no leading zeroes nor spaces). This is useful if you don't want your hack to have a hint on the maximum number of digits the number can have. Very useful for compact display since the “characters” are positioned to the left or right as possible.

Notes:
  • Prior to writing the numbers to the status bar/overworld border (Overworld Border plus patch), you must have clear the tiles that would be overwritten by the digits so that if they got changed (“10” becomes a “9”), the tile that “disappeared” doesn't end up staying there and be duplicated (“10” becomes “90”, where the “0” tile wasn't cleared)


See the code here. In the event the work gets (falsely taken down (I mean, this have shown how easy to abuse takedown notices, therefore no post is safe)), I've posted a copy here:

Defines:

Code
;SA-1 detection (don't touch)
if defined("sa1") == 0
	!dp = $0000
	!addr = $0000
	!sa1 = 0
	!gsu = 0

	if read1($00FFD6) == $15
		sfxrom
		!dp = $6000
		!addr = !dp
		!gsu = 1
	elseif read1($00FFD5) == $23
		sa1rom
		!dp = $3000
		!addr = $6000
		!sa1 = 1
	endif
endif

;RAM locations
if !sa1 == 0
 !Scratchram_CharacterTileTable = $7F844A
else
 !Scratchram_CharacterTileTable = $400198
endif
 ;^[X bytes] A table containing strings of "characters"
 ; (more specifically digits). The number of bytes used
 ; is how many characters you would write.
 ; For example:
 ; -If you want to display a 5-digit 16-bit number 65535,
 ;  that will be 5 bytes.
 ; -If you want to display [10000/10000], that will be
 ;  11 bytes (there are 5 digits on each 10000, plus 1
 ;  because "/"; 5 + 5 + 1 = 11)

!StatusbarFormat = $02
 ;^Number of grouped bytes per 8x8 tile:
 ; $01 = Minimalist/SMB3 [TTTTTTTT, TTTTTTTT]...[YXPCCCTT, YXPCCCTT]
 ; $02 = Super status bar/Overworld border plus [TTTTTTTT YXPCCCTT, TTTTTTTT YXPCCCTT]...
 
!StatusBar_UsingCustomProperties           = 0
 ;^Set this to 0 if you are using the vanilla SMW status bar or any status bar patches
 ; that doesn't enable editing the tile properties, otherwise set this to 1 (you may
 ; have to edit "!Default_GraphicalBarProperties" in order for it to work though.).
 ; This define is needed to prevent writing what it assumes tile properties into invalid
 ; RAM addresses.

!BlankTile = $FC
 ;^Tile number for where there is no characters to be written for each 8x8 space.

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


Routines:
Code
incsrc "../DisplayStringDefines/Defines.asm"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;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.
;
;Note: Because SA-1's multiplication/division registers are signed,
;values over 32,767 ($7FFF) will glitch when you patch SA-1 on your
;game. Therefore, I added a Sa-1 detection to use an unsigned division
;as the SNES registers become inaccessible on SA-1 mode.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Suppress Leading zeros via left-aligned positioning
;
;This routines takes a 16-bit unsigned integer (works up to 5 digits),
;suppress leading zeros and moves the digits so that the first non-zero
;digit number is located where X is indexed to. Example: the number 00123
;with X = $00:
;
; [0] [0] [1] [2] [3]
;
; Each bracketed item is a byte storing a digit. The X above means the X
; index position.
; After this routine is done, they are placed in an address defined
; as "!Scratchram_CharacterTileTable" like this:
;
;              X
; [1] [2] [3] [*] [*]...
;
; [*] Means garbage and/or unused data. X index is now set to $03, shown
; above.
;
;Usage:
; Input:
;  -!HexDecDigitTable to !HexDecDigitTable+4 = a 5-digit 0-9 per byte (used for
;   1-digit per 8x8 tile, using my 4/5 hexdec routine; ordered from high to low digits)
;  -X = the location within the table to place the string in.
; Output:
;  -!Scratchram_CharacterTileTable = A table containing a string of numbers with
;   unnecessary spaces and zeroes stripped out.
;  -X = the location to place string AFTER the numbers. Also use for
;   indicating the last digit (or any tile) number for how many tiles to
;   be written to the status bar, overworld border, etc.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SupressLeadingZeros:
	LDY #$00				;>Start looking at the leftmost (highest) digit
	LDA #$00				;\When the value is 0, display it as single digit as zero
	STA !Scratchram_CharacterTileTable,x	;/(gets overwritten should nonzero input exist)

	.Loop
	LDA.w !HexDecDigitTable|!dp,Y		;\If there is a leading zero, move to the next digit to check without moving the position to
	BEQ ..NextDigit				;/place the tile in the table
	
	..FoundDigit
	LDA.w !HexDecDigitTable|!dp,Y		;\Place digit
	STA !Scratchram_CharacterTileTable,x	;/
	INX					;>Next string position in table
	INY					;\Next digit
	CPY #$05				;|
	BCC ..FoundDigit			;/
	RTL
	
	..NextDigit
	INY			;>1 digit to the right
	CPY #$05		;\Loop until no digits left (minimum is 1 digit)
	BCC .Loop		;/
	INX			;>Next item in table
	RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Convert left-aligned to right-aligned.
;
;Use this routine after calling SupressLeadingZeros and before calling
;WriteStringDigitsToHUD. Note: Be aware that the math of handling the address
;does NOT account to changing the bank byte (address $XX****), so be aware of
;having status bar tables that crosses bank borders ($7EFFFF, then $7F0000,
;as an made-up example, but its unlikely though).
;
;Input:
; -$00-$02 = 24-bit address location to write to status bar tile number.
; -If tile properties are edit-able:
; --$03-$05 = Same as $00-$02 but tile properties.
; --$06 = the tile properties.
; -X = The number of characters to write, ("123" would have X = 3)
;Output:
; -$00-$02 and $03-$05 are subtracted by [(NumberOfCharacters-1)*!StatusbarFormat]
;  so that the last character is always at a fixed location and as the number
;  of characters increase, the string would extend leftwards. Therefore,
;  $00-$02 and $03-$05 before calling this routine contains the ending address
;  which the last character will be written.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ConvertToRightAligned:
	TXA
	DEC
	TAY					;>Transfer status bar leftmost position to Y
	BRA +
ConvertToRightAlignedFormat2:
	TXA
	DEC
	ASL
	TAY					;>Transfer status bar leftmost position to Y
	+
	REP #$21				;\-(NumberOfTiles-1)...
	AND #$00FF				;|
	EOR #$FFFF				;|
	INC A					;/
	ADC $00					;>...+LastTilePos (we are doing LastTilePos - (NumberOfTiles-1))
	STA $00					;>Store difference in $00-$01
	SEP #$20				;\Handle bank byte
;	LDA $02					;|
;	SBC #$00				;|
;	STA $02					;/
	
	if !StatusBar_UsingCustomProperties != 0
		TYA
		DEC
		ASL
		REP #$21				;\-(NumberOfTiles-1)
		AND #$00FF				;|
		EOR #$FFFF				;|
		INC A					;/
		ADC $03					;>+LastTilePos (we are doing LastTilePos - (NumberOfTiles-1))
		STA $03					;>Store difference in $00-$01
		SEP #$20				;\Handle bank byte
;		LDA $05					;|
;		SBC #$00				;|
;		STA $05					;/
	endif
	RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Write aligned digits to Status bar/OWB+
;
;Input:
; -$00-$02 = 24-bit address location to write to status bar tile number.
; -If tile properties are edit-able:
; --$03-$05 = Same as $00-$02 but tile properties.
; --$06 = the tile properties.
; -X = The number of characters to write, ("123" would have X = 3)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WriteStringDigitsToHUD:
	DEX
	TXY
	
	.Loop
	LDA !Scratchram_CharacterTileTable,x
	STA [$00],y
	if !StatusBar_UsingCustomProperties != 0
		LDA $06
		STA [$03],y
	endif
	DEX
	DEY
	BPL .Loop
	RTL
WriteStringDigitsToHUDFormat2:
	DEX
	TXA				;\SSB and OWB+ uses a byte pair format.
	ASL				;|
	TAY				;/
	
	.Loop
	LDA !Scratchram_CharacterTileTable,x
	STA [$00],y
	if !StatusBar_UsingCustomProperties != 0
		LDA $06
		STA [$03],y
	endif
	DEX
	DEY #2
	BPL .Loop
	RTL


Example:

Code
incsrc "../DisplayStringDefines/Defines.asm"

!MaxChar	= 5
 ;^Max number of characters to write, also how many tiles to clear
 ; so that no leftover tiles appear when it should disappear.
 ; i.e "65535/65535" is 11 characters.
!AlignMode	= 1
 ;0 = left-aligned
 ;1 = right-aligned
 
!Freeram_FirstNumb	= $60
!Freeram_SecondNumb	= $62
 ;^[2 bytes] the numbers to be displayed.

if !AlignMode == 0
 if !sa1 == 0
  !StatusBarPos = $7FA000
 else
  !StatusBarPos = $404000
 endif
else
 if !sa1 == 0
  !StatusBarPos = $7FA03E
 else
  !StatusBarPos = $40403E
 endif
endif
 ;^Status bar position to write. When left-aligned, this represents the first tile address,
 ; if right-aligned, this is the last tile position (will occupy tiles this and BEFORE it).

main:

	LDA $15			;\These are to increase or decrease number via controller
	BIT.b #%00001000	;|For testing numbers when they move to another tile when
	BNE .Up			;|the number of digits changes.
	BIT.b #%00000100	;|UP/DOWN = FirstNumb
	BNE .Down		;|Left/RIGHT = SecondNumb
	BRA +
	
	.Up
	REP #$20
	LDA !Freeram_FirstNumb
	INC A
	STA !Freeram_FirstNumb
	SEP #$20
	BRA +
	
	.Down
	REP #$20
	LDA !Freeram_FirstNumb
	DEC A
	STA !Freeram_FirstNumb
	SEP #$20
	
	+
	
	LDA $15
	BIT.b #%00000001
	BNE .Left
	BIT.b #%00000010
	BNE .Right
	BRA +
	
	.Left
	REP #$20
	LDA !Freeram_SecondNumb
	INC A
	STA !Freeram_SecondNumb
	SEP #$20
	BRA +
	
	.Right
	REP #$20
	LDA !Freeram_SecondNumb
	DEC A
	STA !Freeram_SecondNumb
	SEP #$20
	
	+
	
	.StatusBarRemoveFrozenTiles
	LDA #$FC							;\Clear out tiles so if the digit
	LDX.b #(!MaxChar-1)*!StatusbarFormat				;|were to disappear, does not leave
	-
	if !AlignMode == 0						;|duplicated digits or frozen tiles.
		STA !StatusBarPos,x					;|
	else								;|
		STA !StatusBarPos-((!MaxChar-1)*!StatusbarFormat),x	;|
	endif								;|
	DEX #2								;|
	BPL -								;/
	
	.WriteStatusBar
	LDA !Freeram_FirstNumb			;\First number HEX->DEC
	STA $00					;|
	LDA !Freeram_FirstNumb+1		;|
	STA $01					;|
	JSL Routines_ConvertToDigits		;/
	LDX #$00				;>Initialize string position
	JSL Routines_SupressLeadingZeros	;>Place only the necessary digits in the string table
	LDA #$26				;\The number separator (its "X" by default, acting as a "/")
	STA !Scratchram_CharacterTileTable,x	;/
	INX					;>Increment X to write next number preceding it
	LDA !Freeram_SecondNumb			;\Do the same thing as above, this time without initalizing X
	STA $00					;|so that it places the second number after the "/".
	LDA !Freeram_SecondNumb+1		;|
	STA $01					;|
	JSL Routines_ConvertToDigits		;|
	JSL Routines_SupressLeadingZeros	;/
	CPX.b #!MaxChar+1			;\If there are more characters than the max, skip status bar write.
	BCS ..TooMuch				;/
	LDA.b #!StatusBarPos : STA $00		;\Set address to write at a given status bar position.
	LDA.b #!StatusBarPos>>8 : STA $01	;|
	LDA.b #!StatusBarPos>>16 : STA $02	;/
	if !AlignMode != 0
		if !StatusbarFormat == $01				;\These offset the write position based on how many
			JSL Routines_ConvertToRightAligned		;|characters so that it is right-aligned.
		else
			JSL Routines_ConvertToRightAlignedFormat2	;|
		endif							;/
	endif
	if !StatusbarFormat == $01					;\Write to status bar
		JSL Routines_WriteStringDigitsToHUD			;|
	else
		JSL Routines_WriteStringDigitsToHUDFormat2		;|
	endif								;/
	..TooMuch
	RTL


Note that this is tested using uberasm tool, so they call via JSL FileNameWithoutExtension_Label

--------------------
Give thanks to RPG hacker for working on Asar.
My 32-bit frame counter to “hours:minutes:seconds.centiseconds” (centiseconds is actually a frame counter from 0 to 59; converted to 0 to 99). Give credit to Akaginite for the division routine.
Code
;Ram Addresses
 !Scratchram_Frames2TimeOutput = $7F844E
 ;^[4 bytes], the output in HH:MM:SS.CC format:
 ;+$00 = hour
 ;+$01 = minutes
 ;+$02 = seconds
 ;+$03 = centiseconds (display 00-99)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Convert frames to timer, By GreenHammerBro
; This routine converts frames into: HH:MM:SS.CC
;
;Unlike my previous stopwatch timer (rejected) and imamelia's,
;the 3 byte of RAM now stores ONE value; the 24-bit frame
;counter, rather than the 3 units of time in each byte.
;
;Input:
;-$00 to $03: the frame value.
;Output:
;-!Scratchram_Frames2TimeOutput (4 bytes): time in real world
; units, mentioned on the above define.
;Overwritten:
;-$00 to $05 was used by division routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Frames2TimerMain:
	LDX #$03
	
	.Loop
	REP #$20					;\divide by 60
	LDA.w #60					;|
	STA $04						;|
	SEP #$20					;/
	JSL MathDiv32_16				;>$00 = quotient (increases every 60 units), $04 = remainder (counter loops 00-59)

	CPX #$01					;\allow hours to go above 59
	BEQ .UnCappedHours				;/
	LDA $04						;\store looped value (frames, seconds and minutes loop 00-59)
	STA !Scratchram_Frames2TimeOutput,x		;/
	
	..Next
	DEX
	BRA .Loop
	
	.UnCappedHours
	LDA $00						;\write hours
	STA !Scratchram_Frames2TimeOutput		;/
	
	.ConvertFramesToCentiseconds
	;simply put [Frames*100/60], highest [Frames*100 should be 5900]
	if !sa1 == 0
		LDA !Scratchram_Frames2TimeOutput+3	;\Frames*100
		STA $4202				;|
		LDA.b #100				;|
		STA $4203				;/
		JSR WaitCalculation			;>Wait 12 cycles in total (8 is minimum needed)
		REP #$20
		LDA $4216				;>load product
		STA $4204				;>Product in dividend
		SEP #$20
		LDA.b #60				;\product divide by 60 (divisor)
		STA $4206				;/
		JSR WaitCalculation			;>Wait 12 cycles (16 is minimum needed)
		NOP #2					;>wait 4 cycles (16 cycles total)
		
		LDX $4214				;>quotient
		LDA $4216				;\if remainder is less than half the divisor, round down
	else
		STZ $2250				;\>multiply mode
		LDA !Scratchram_Frames2TimeOutput+3	;|Frames*100
		STA $2251				;|
		STZ $2252				;|
		LDA.b #100				;|
		STA $2253				;|
		STZ $2254				;/>this should start the calculation
		NOP					;\Wait 5 cycles
		BRA $00					;/
		REP #$20
		LDA $2306				;\backup the value in case of setting $2250 to divide
		STA $00					;/causes $2306 to lose its product
		LDX #$01				;\divide mode
		STX $2250				;/
		LDA $00					;\product divide by...
		STA $2251				;/
		SEP #$20
		LDA.b #60				;\60
		STA $2253				;/
		STZ $2254				;>this triggers the calculation to run
		NOP					;\Wait 5 cycles
		BRA $00					;/
		
		LDX $2306				;>Quotient
		LDA $2308
	endif
	CMP.b #30
	BCC ..NoRound
	
	..Round
	INX					;>round up quotient
	
	..NoRound
	TXA
	STA !Scratchram_Frames2TimeOutput+3
	RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Unsigned 32bit / 16bit Division
; By Akaginite (ID:8691), fixed the overflow
; bitshift by GreenHammerBro (ID:18802)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Arguments
; $00-$03 : Dividend
; $04-$05 : Divisor
; Return values
; $00-$03 : Quotient
; $04-$05 : Remainder
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MathDiv32_16:	REP #$20
		ASL $00
		ROL $02
		LDY #$1F
		LDA.w #$0000
-		ROL A
		BCS +
		CMP $04
		BCC ++
+		SBC $04
		SEC
++		ROL $00
		ROL $02
		DEY
		BPL -
		STA $04
		SEP #$20
		RTL

if !sa1 == 0
	WaitCalculation:	;>The register to perform multiplication and division takes 8/16 cycles to complete.
	RTS
endif

If you input a value #$0004F1A0 (324000 decimal frames: 1 hour and 30 minutes), it outputs:
Code
-!Scratchram_Frames2TimeOutput is 1, the hour
-!Scratchram_Frames2TimeOutput+1 is 30 (#$1E in hex) the minutes
-!Scratchram_Frames2TimeOutput+2 is 00, this is the seconds
-!Scratchram_Frames2TimeOutput+3 is 00, this is the approximate centiseconds.


Not to be confused with the old timer generators found on the sprite section (actually rejected due to smwc updating sections when UberasmTool hit the scene), this one is different:

  • The value representing the amount of time is a single value stored in 32-bit (low endian; like the SNES would do) indicating a frame counter. The other codes that tries to replicate the real world timer stores 3 units of time in each byte: minutes:seconds:frames, where each value are handled individually rather than one, so if a value were to go past a certain threshold, say if frames reaches 60, it increases the seconds byte, and of course if it was a countdown, (frames goes down past 00), it would decrease the seconds byte (remember that the game runs at 60FPS).

    Using my method, it makes it easier if you are manipulating time using math operators, such as adding a minute to the countdown, you simply use this code:
    Code
    REP #$20
    LDA !Freeram_TimeFrames
    CLC
    ADC.w #3600		;>3600 frames = 1 minute (60frames/seconds times 60)
    STA !Freeram_TimeFrames
    LDA !Freeram_TimeFrames+2
    ADC #$0000
    STA !Freeram_TimeFrames+2
    SEP #$20

  • Because this is an input/output based subroutine, you can have multiple different timers use this without any issues, other timers that had its value stores it units separately uses the freeram directly and you had to rewrite the code with different RAM to store the time amount


To have a timer the increments/decrements, use this code:
Code
!Freeram_Time = $60
;^[4 bytes] frame counter

REP #$20
LDA !Freeram_Time
CLC			;\not to use INC because it doesn't set carry
ADC #$0001		;/when the value overflows a 16-bit boundary (#$FFFF)
STA !Freeram_Time
LDA !Freeram_Time+2	;\high word
ADC #$0000		;|
STA !Freeram_Time+2	;/
SEP #$20

For decrements (countdown), simply replace the CLC and 2 ADCs (not the number next to the opcode) with SEC and 2 SBCs.

Unit conversion to frames (as “frms”) template:
Code
                   1 sec =     60 frms
        1 min =   60 sec =   3600 frms
1 hr = 60 min = 3600 sec = 216000 frms

Formula:

Frames = (Hours*216000)+(Minutes*3600)+(Seconds*60)



Code to set (write) the timer value:

Code
!Freeram_Timer = $60
!StartTimerHour = 0
!StartTimerMinute = 3
!StartTimerSeconds = 30
	REP #$20
	LDA.w #(!StartTimerHour*216000)+(!StartTimerMinute*3600)+(!StartTimerSeconds*60)
	STA !Freeram_Timer
	LDA.w #(!StartTimerHour*216000)+(!StartTimerMinute*3600)+(!StartTimerSeconds*60)>>16
	STA !Freeram_Timer+2
	SEP #$20


Code to compare the time with another value (greater than/equal to and less than):

Code
!CompareTimerHour = 0
!CompareTimerMinute = 1
!CompareTimerSeconds = 0

!CompareFramesLowWord = (!CompareTimerHour*216000)+(!CompareTimerMinute*3600)+(!CompareTimerSeconds*60)
!CompareFramesHighWord = (!CompareTimerHour*216000)+(!CompareTimerMinute*3600)+(!CompareTimerSeconds*60)>>16
;^Placed like this because table stretched if the whole formula was applied in the code

	REP #$20
	LDA !Freeram_Timer				;\CMP sets the carry should A >= compare value (CMP is like SBC)
	CMP.w #!CompareFramesLowWord			;/following SBC would subtract an additional 1 if carry is clear (borrowing)
	LDA !Freeram_Timer+2				;\SBC would set the carry should A subtract by subtrahend
	SBC #!CompareFramesHighWord			;/if subtrahend was smaller than A (clear carry if underflow occurs)
	SEP #$20

	;Carry (BCC/BCS) = set should timer is above or equal to a value.


Compare if equal or not (best for executing events for 1 frame):
Code
!CompareTimerHour = 0
!CompareTimerMinute = 1
!CompareTimerSeconds = 0

!CompareFramesLowWord = (!CompareTimerHour*216000)+(!CompareTimerMinute*3600)+(!CompareTimerSeconds*60)
!CompareFramesHighWord = (!CompareTimerHour*216000)+(!CompareTimerMinute*3600)+(!CompareTimerSeconds*60)>>16

	REP #$20
	LDA !Freeram_Timer
	CMP.w #!CompareFramesLowWord
	BNE .NotEqual
	LDA !Freeram_Timer+2
	CMP #!CompareFramesHighWord
	BNE .NotEqual
	SEP #$20
	
	.Equal
	
	.NotEqual
	SEP #$20	;>remove this if you continue 16-bit A


2/24/2018 Edit: improved the division loop routine in the frames -> Hours:Minutes:Seconds:Centiseconds, it no longer holds a duplicate code, and the format stores the units from hours to frames instead the other way around, thus making loops to write to the status bar/HUD more easier to work with.

--------------------
Give thanks to RPG hacker for working on Asar.
32-bit unsigned hex-dec, great for numbers greater than 65535:
Code
!NumOfDigits = 6
;^Number of digits to be stored. Up to 10 because maximum
; 32-bit unsigned integer is 4,294,967,295.

!Scratchram_32bitHexDecOutput = $7F844E
;^[bytes_used = !NumOfDigits] The output
; formatted each byte is each digit 0-9.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;32-bit hex-dec converter
;input:
;-$00-$03 = the 32-bit number in question.
;output:
;-!Scratchram_32bitHexDecOutput to
; (!Scratchram_32bitHexDecOutput+!NumOfDigits)-1:
; Contains value 0-9 per byte; starting at the last
; byte would be the ones place, before that is the
; tens, and so on (binary coded decimal, big endian
; digits).

;Overwritten
;-$04 to $05: because remainder of the division.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	Convert32bitIntegerToDecDigits:
	LDX.b #!NumOfDigits-1
	
	.Loop
	LDA.b #10				;\divide by 10 (the radix)
	STA $04					;|
	STZ $05					;/
	JSL MathDiv32_16			;>divide.
	LDA $04					;\write remainder digit (obviously shouldn't exceed 255)
	STA !Scratchram_32bitHexDecOutput,x	;/
	
	..Next
	DEX					;\loop until all digits are written
	BPL .Loop				;/
	RTL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Unsigned 32bit / 16bit Division
; By Akaginite (ID:8691), fixed the overflow
; bitshift by GreenHammerBro (ID:18802)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Arguments
; $00-$03 : Dividend
; $04-$05 : Divisor
; Return values
; $00-$03 : Quotient
; $04-$05 : Remainder
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MathDiv32_16:	REP #$20
		ASL $00
		ROL $02
		LDY #$1F
		LDA.w #$0000
-		ROL A
		BCS +
		CMP $04
		BCC ++
+		SBC $04
		SEC
++		ROL $00
		ROL $02
		DEY
		BPL -
		STA $04
		SEP #$20
		RTL


Remove leading zeroes (same as my 4-5 hexdec, but changeable with how many digits you are going to use):
Code
RemoveLeadingZeroes:
	LDX #$00
	
	.Loop
	LDA !Scratchram_32bitHexDecOutput,x	;\if current digit non-zero, don't omit trailing zeros
	BNE .NonZero				;/
	LDA #$FC				;\blank tile to replace leading zero
	STA !Scratchram_32bitHexDecOutput,x	;/
	INX					;>next digit
	CPX.b #!NumOfDigits-1			;>last digit to check (tens place). So that it can display a single 0.
	BCC .Loop				;>if not done yet, continue looping.
	
	.NonZero
	RTL


--------------------
Give thanks to RPG hacker for working on Asar.
Originally posted by Akaginite
this code is implemented by my experience, but I can't prove mathematically why it works fine. I'm silly.

You're adding (operand) x 0x10000, and since n + (-n) is 0x10000 (we just ignore the carry normally), there's why it works.
I've noticed that Akaginite's 32-bit/16-bit division routine have a bug on it where the bitshift overflow can happen and outputs the wrong values. This happens when the value in A (up to 16-bits can be processed at a time) gets ASL A'ed when A holds a value $8000+, which ends up with bit 15 transferred to the carry without being checked (discarded), then compares this broken value to $04 (which can assume that this large value is less than $04) and incorrectly flags this value as less than and screws up the result. I've added a carry check and SEC (because it's expected that after the SBC operation, carry is ALWAYS set) and this bug is fixed.

This bug can easily happen if you were to have the (unsigned) 32bit integer #$80000000 or more (in binary, that is a 1 on the leftmost digit and 31 zeroes after or more), as the glitch triggers right away on the first loop on ASL A.
Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Unsigned 32bit / 16bit Division
; By Akaginite (ID:8691), fixed the overflow
; bitshift by GreenHammerBro (ID:18802)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Arguments
; $00-$03 : Dividend
; $04-$05 : Divisor
; Return values
; $00-$03 : Quotient
; $04-$05 : Remainder
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MathDiv32_16:	REP #$20
		ASL $00
		ROL $02
		LDY #$1F
		LDA.w #$0000
-		ROL A
		BCS +
		CMP $04
		BCC ++
+		SBC $04
		SEC
++		ROL $00
		ROL $02
		DEY
		BPL -
		STA $04
		SEP #$20
		RTL


--------------------
Give thanks to RPG hacker for working on Asar.
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.

Copyright © 2005 - 2019 - SMW Central
Legal Information - Privacy Policy - Link To Us


Total queries: 9

Menu

Follow Us On

  • YouTube
  • Twitch
  • Twitter

Affiliates

  • Talkhaus
  • SMBX Community
  • GTx0
  • Super Luigi Bros
  • ROMhacking.net
  • MFGG
  • Gaming Reinvented