Register - Login
Views: 99380120
Main - Memberlist - Active users - Calendar - Wiki - IRC Chat - Online users
Ranks - Rules/FAQ - Stats - Latest Posts - Color Chart - Smilies
04-23-22 11:16:58 PM
Jul - SM64 Hacking (Archive) - ASM hacking New poll - New thread - New reply
Pages: 1 2 3 Next newer thread | Next older thread
yoshiman
Member
Level: 23


Posts: 68/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 05-19-08 01:28:43 AM Link | Quote
Don't worry if you know nothing about the N64's ASM as I'm here to help and I'll start off simple and then use examples to show you how the game works and how it can be altered to go beyond simple level editing.

The N64's processor is a RISC (Reduced Instruction Set Computing) so its instructions are quite simple and are designed logically with each instruction using 4 bytes (32-bits). Remember that Nintendo most likely used C or C++ to program SM64 so we will be actually looking at the result when converted to ASM. This means you may see coding that looks a little strange but is actually very logical.

Some important registers that are used for temporary storage:

r0 is register zero which always contains the value zero so it can be used as a constant and also for arithmetic operations.

sp is the stack pointer which you can ignore as long as you don't change it

Then there are various others such as at, a3, vo, etc.

The N64's processor features offset calculations which is ideal when it comes to reading or writing to a certain variable in an object structure. You'll often see in the behaviour coding that a register will be loaded with a pointer-to-object value and then an offset will be added to get at the variable.

Being 64-bit you need to know:

double word=64-bit
word=32-bit
half world=16-bit
byte=8-bit

Although the processor's instructions can read or write up to 64-bits from memory, immediate data (i.e. values that are part of the instruction) can only be up to 16-bit. This is the reason that Gameshark codes on a real N64 cheat device only allow up to 16-bits for the code.

That's you starter.

James S.

____________________
We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 98/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 05-19-08 03:06:42 AM (last edited by messiaen at 05-19-08 11:03 AM) Link | Quote
Some useful reference:

N64 opcodes by Anarko
Dextrose.com - Assemblers/Disassembler and lots of tools for N64.
MIPS Registers
Programmed Instroduction to MIPS Assembly Language

Concerning emulators, Nemu has disassembler/RAM viewer features, so this is a must get. If you want to test the disassembler, use the RAM viewer and go to one of the adresses pointed by the 0x0C behavior command. For instance:

ROM Addr: 0021B098 Hex Behav: 13001298
Description: Multiple Coins
21B098/001298 00 08 00 00
21B09C/00129C 11 01 00 41
21B0A0/0012A0 35 00 00 00
21B0A4/0012A4 08 00 00 00
21B0A8/0012A8 0C 00 00 00 80 2A FC E4
21B0B0/0012B0 09 00 00 00

At RAM address 802AFCE4, the data will start with 27BD (ADDIU SP, SP, XXXX). Look for the next 27BD and you have the end of this code segment (is this right James?), usually precedeed by a NOP, a series of 0 bytes.

Edit: Renegade 64 seems a nice tool. It can attach to a running emulator view memory, assemble/disassemble plus other functions.
Also, this build of Project64 has debugging features.
Rachel Mae

Creature of Chaos
Level: 141


Posts: 820/5929
EXP: 33575022
For next: 544992

Since: 07-03-07

Pronouns: she/her
From: Foxglen

Since last post: 11 days
Last activity: 2 days

Posted on 05-19-08 09:08:38 PM (last edited by Neko54123 at 05-19-08 06:09 PM) Link | Quote
This was originally in reply to a thread by wowfunhappy re: implementing GameShark codes directly into ROM, but it was deleted before I could reply to it, so I might as well post it here:

Originally posted by me, duh
The problem is that modifying a game's ROM code is sometimes much more difficult than simply modifying RAM. For example, say a game's debug mode is activated by changing a RAM address to 01. If the code that originally wrote a 01 to that address is no longer present in the ROM, you either have to recreate the routine (find an empty spot in the ROM, add the code, and insert a jump to the routine at an appropriate location), or find all the debug routines in the ROM that read that value and modify them to execute regardless of its setting.

So yeah, it's possible, but there's no way to do it easily, or automatically.



____________________
yoshiman
Member
Level: 23


Posts: 69/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 05-19-08 09:12:10 PM (last edited by yoshiman at 05-19-08 08:54 PM) Link | Quote
Yes, at the start of a function and at the end the register sp (stack pointer) will be modified. However, make sure you follow the jumps and brances carefully and there will be a lot of them for most objects. Remember, jumps and branches use the delay slot so the next instruction will be executed before the jump/branch but Nemu will tell you.

Today I went one better and changed the coding so that exploded Bob-ombs are replaced with King Bob-omb! It's amazing, you can fight loads of them (as can be seen in my YouTube video (yoshielectron) and get a star from each of them. Also, take note of what happens to the music which I was unable to show in the video due to the short length.

I tried the debug Project64 and although it's a great help it's a bit lacking for my needs. For example, you can only set a breakpoint when the pc is at a certain address; Nemu allows you to halt the game when the CPU reads or writes to a specific address.

James S.

____________________
We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 99/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 05-20-08 01:33:41 AM (last edited by messiaen at 05-20-08 09:03 AM) Link | Quote
Could you give some help concerning breakpoints? I couldn't figure out effective ways to use them in Nemu (remember I'm a absolute begginer in ASM!). I found what seems to be a very generic "Break on Opcode" function on the interface, but how can I set it to break on a specific instruction (example, one of the JALs after a conditional) ?

What I'm trying to do is supress traits of behaviors from some of the 0x0C calls. A few days ago I tried noping a few jump instructions and found the instruction (that is, the jump) responsible for displaying the Bob-Omb dialogue after he is thrown from the cliff and gets respawned at the top of the mountain, however probably there is a quicker way to find that using breakpoints.

Also, some commented code would be very nice .
yoshiman
Member
Level: 23


Posts: 70/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 05-20-08 08:51:03 PM Link | Quote
I'll add some examples later but first about Nemu and seting breakpoints. Most likely you will want to set up a breakpoint when the game reads and/or writes to a specific vaiable belonging to an object. Someone requested I do a hack so that the Bob-ombs do not react at all to Mario so I used Nemu.

First of all I found a Bob-omb in memory using Nemu's memory viewer and then went to offset 0xF8. I knew that when that variable has the value 0x01 the Bob-omb ignites so I had the write option only checked and then right-clicked on the memory location.

The game will continue playing but as soon as the Bob-omb tries to ignite itself Nemu paused the game allowing me to check out the coding. For other objects there maybe many times that a certain variable is read or written to so you may have to click 'Go' to jump to the next read/write of that variable.

Remember, emulators are a pain if you want to change coding, I've found that you have to edit the RAM or activate the code(s) before the title screen.

James S.

____________________
We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 102/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 05-20-08 09:27:02 PM Link | Quote
Thanks James, that was very helpful! I didn't known that I had to right-click in order to enable the watch on a specific memory .

I looked at the RAM Editing thread and things are getting clearer regarding the "RAM objects". Your RAM map for them will certainly be very useful.

I'll spend a few days playing with breakpoints and trying to understand some of the opcodes.
yoshiman
Member
Level: 23


Posts: 71/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 05-20-08 10:03:08 PM (last edited by yoshiman at 05-21-08 08:30 PM) Link | Quote
I'll upload here (Editing the RAM objects) and to my site an updated list of the uses of the object variables. Looking at the ASM you can confirm the size of various variables which really helps with listing what each variable does. For example, if you see something like:

lh t6, 0x0014(v0)

Then you know that the variable at offset 0x0014 is 16-bit, though that's a general rule and may not always apply.

In one of my recent videos the code caused Bob-ombs to be spawned from trees instead of leaves. Here is the coding that spawns the leaves:

802B0AB4 lui a2, 0x1300
802B0AB8 addiu a2, a2, 0x13C4
802B0ABC lw a0, 0x1160(a0)
802B0AC0 jal 0x8029EDCC
802B0AC4 addiu a1, r0, 0x00a2

0xa2 is the gfx ID for a leaf and 0x1313C4 is the segment/offset pointer to the leaf's behaviour.

____________________
We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 156/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 07-03-08 10:47:22 PM Link | Quote
Sorry for taking so long to reply this, but this is very interesting!

Is this code called somewhere from the tree behavior 0x0C call (0x802C63E8) ? I'm still learning about the stack pointer and return addresses, but is it possible to backtrack from this code up to the tree behavior call? I ask this because it would be nice to discover the function of most of the "unused" behaviors. I think this would be possible for behaviors which are connected, in this case, tree and leaves. In other behaviors, this kind of connection is explicit, such in the King Bob-Omb and Bowser, which have 'sub-ojects' created with a 0x29, 0x1c or 0x2c behavior command.

Correct me if I'm wrong. So, the JAL 0x8029EDCC is probably used to create another object, and the registers a2 and a1 provide two arguments: the first (a1) is the Model ID, in that case 0x00a2, and the second argument (a2) is the leaves behavior (0x130013C4). What strikes me is that the format is very similar to the 0x24 level command, but with fewer arguments.
yoshiman
Member
Level: 23


Posts: 83/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 07-04-08 10:19:57 PM Link | Quote
There seems to be at least 2 spawn object functions, a simpler version requires the GFX ID and segment/offset behaviour as well as a pointer to the object whose behaviour spwaned the new object. This pointer could be used for many purposes but for one it is used to look up the position of the parent object in order to place the starting point for the child object.

Using Nemu, you can trace back or at least take note of return addresses in order to find functions that call another. A trick I've used is to spawn an object (such as a leaf), search for its graphics which will lead to the actual object. Looking at the object in the RAM it will have its behaviour pointers and I can also find its GFX ID anyway. Then you can calculate the segment/offset and search for that thus leading to the function(s) that spwan an object with that behaviour.

____________________
James S.

We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 157/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 07-05-08 07:50:21 PM (last edited by messiaen at 07-05-08 05:17 PM) Link | Quote
Ok, I did a little searching, and I think I found two more spawn functions. Take a look and see if they are the same you know. The 0x802F2C84 call of the "Hidden Red Coin Star Behavior" (Behav 0x3E8C) actually spawns many objects:

802F2CA0: LUI A0, 0x8036 <- A question about this. Is this the base address used when writing/reading from memory? That is, 0x80360000
802F2CA4: LUI A2, 0x1300 <- Behavior bank. This is a quite nice string to search when looking for spawn functions. Another way is to look for all the "JALs" below, they happen quite often.
802F2CA8: ADDIU A2, A2, 0x556C <- "Unknown" Behavior, but at least now we know it is related to the Hidden Red Coin Star Behavior.
802F2CAC: LW A0, 0x1160 (A0)
802F2CB0: JAL 0x8029EDCC
802F2CB4: ADDIU A1, R0, 0x0079 <- Model 79 = "Transparent Star". Hmm, so probably Behavior 0x556C is linked to the Transparent Star?

Maybe there is a branch code earlier, so the transparent star is actually skipped (ie, checks if you don't have the star).

802F2CB8: LUI A0, 0x1300
802F2CBC: JAL 0x8029FBDC <- Hmm, could this be another spawn function ? I found this one also on one of the "check points" code.
802F2CC0: ADDIU A0, A0, 0x3EAC <- Red coin behavior!
802F2CC4: SH V0, 0x0036 (SP)
802F2CC8: LH T7, 0x0036 (SP)
802F2CCC: BNEZ T7, 0x802F2D5C
802F2CD0: NOP
802F2CD4: LUI T8, 0x8036
802F2CD8: LW T8, 0x1160 (T8)
802F2CDC: LUI A3, 0x1300 <- Here we go again.
802F2CE0: ADDIU A3, A3, 0x3E3C <- Collect Star Behavior. It probably doesn't a model ID because the Collect Star behavior has it already hardcoded, hardcoded in one of its 0x0C calls.
[...] lots of code here [...]
802F2D30: JAL 0x8029E9AC -> Used a lot, probably another spawn function
yoshiman
Member
Level: 23


Posts: 84/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 07-06-08 11:25:55 PM Link | Quote
I know more the PAL addresses but I'm making more of an effort to add NTSC functions to my list. Before an offset type of instruction is used a base address is loaded but remember that if the offset is 0x8000 or higher then it will behave as a minus value.

For e.g., (PAL)

LUI T0,0x8033
LW T0,0xED90(T0)

The word will be loaded from address 0x8032ED90 not 0x8033ED90.

You can test functions by writing your own mini program and include them, this is what I have been doing with my more advanced codes such as spawn 1ups.

____________________
James S.

We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 159/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 07-07-08 11:46:55 PM (last edited by messiaen at 07-08-08 01:28 PM) Link | Quote
Thanks for warning me that these are bit-signed, you saved me from some future frustation . Also, now I understand the "push and pop" stack operations at the beggining/end of each function: the ADDIU instruction is in fact a subtraction operation, creating room for something to be stored (at least the Return Address).

I looked at more spawn functions. This is the code that runs when you get the 100th coin:

802AB558: ADDIU SP, SP, 0xFFE0
802AB55C: SW RA, 0x0014 (SP)
802AB560: SW A0, 0x0020 (SP)
802AB564: LUI A0, 0x8036
802AB568: LUI A2, 0x1300
802AB56C: ADDIU A2, A2, 0x080C
802AB570: LW A0, 0x1160 (A0)
802AB574: JAL 0x8029EDCC

So, it creates a "pseudo-object" with behavior 0x080C, another of the "Unused" ones. Just to clarify, VL-Tone probably called these behaviors "unused" because they aren't used directly in the level scripts object commands. Here is the behavior called:

ROM Addr: 0021A60C Hex Behav: 1300080C
>>>>>>>>>>Unused Behavior? (Runs when you get 100 coins)
21A60C/00080C 00 06 00 00
21A610/000810 11 01 00 01
21A614/000814 2D 00 00 00
21A618/000818 0C 00 00 00 80 2A AF 48
21A620/000820 08 00 00 00
21A624/000824 0C 00 00 00 80 2A B1 C8
21A62C/00082C 09 00 00 00

If I remove the 0x0C calls from this, a star model will still be spawned, but without its normal "Collect Star" behavior.

I tried to insert the "Running Star" behavior I posted earlier at 0x080C, and the result was funny: a running star is spawned. However, it is spawned right at the Mario position, so you automatically get it when you reach the 100th coin.
Stevoisiak
Member
Level: 38


Posts: 95/283
EXP: 345476
For next: 24971

Since: 11-22-07

From: New York, Long Island

Since last post: 12.3 years
Last activity: 5.6 years

Posted on 07-08-08 08:10:51 PM (last edited by Stevoisiak at 07-08-08 05:11 PM) Link | Quote
Originally posted by messiaen
I tried to insert the "Running Star" behavior I posted earlier at 0x080C, and the result was funny: a running star is spawned. However, it is spawned right at the Mario position, so you automatically get it when you reach the 100th coin.

Well, the 100 coin star behaves slightly differently than a regular star, so I think you need some type of code from the star spawn script.
yoshiman
Member
Level: 23


Posts: 85/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 07-08-08 08:25:55 PM Link | Quote
Don't worry too much about the stack unless you plan to make major changes or write your own programs. For e.g, with a code of mine that spawned an object at Mario's position, I saved RA (the return address) on the stack before calling the spawn function since the RA would be changed by the function that's called. After the function the return address is retrieved from the stack.

Speaking of functions, don't forget that the MIPS process has a delay slot with a lot of its instructions that feature branches or jumps; this is something that Nemu will remind you. You might have:

jal xxxxxxxx
lui a0, 0xC84A

So, the lui instruction would be executed before the jump. With coding that calls a spawn function you will often see the behaviour or gaphic ID loaded into a register using an instruction after the function call, which is executed before the call.

____________________
James S.

We English do things a little differently...Anyone for a cup of tea while we hack?!
messiaen
Catgirl
Level: 68


Posts: 161/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 07-08-08 08:54:33 PM (last edited by messiaen at 07-09-08 10:35 AM) Link | Quote
I have read about the delay slot, but with your example it became clearer. I was indeed wondering why the Model ID argument came after the JAL. Is it correct to think that for custom code it is safer to include a NOP after each JAL and BEQ or isn't this necessary (unless space is REALLY an issue) ?

Also, this table shows that registers a0-a3 (arguments) are preserved accross calls. So, there is no need to store it in the stack before a BEQ or JAL instruction?

--

Stevoisiak: You're right about the different behavior. Before the star is spawned, there is an animation, so the star is not spawned right on Mario. However, keeping this behavior seems to nulify the added "Koopa" effect.
yoshiman
Member
Level: 23


Posts: 87/95
EXP: 67008
For next: 715

Since: 12-21-07

From: London, England

Since last post: 13.2 years
Last activity: 12.9 years

Posted on 07-09-08 08:15:37 PM Link | Quote
What you have to remember about the delay slot is that the instruction following the jump or branch will be executed if the call is made or not. So the only time a nop should follow a jump or branch is if there is no instruction to be executed before the call that is also to be executed after the call. If you ask me, having these extra nop's that are actually wasting space are annoying but necessary.

As for the table you showed, is that specific to the N64-the MIPS processors were used in other consoles and devices. There's no harm in looking at a function you want to call to see if it modifies certain registers, if it does, typically at the beginning of the function it will save them to the stack before altering them.

____________________
James S.

We English do things a little differently...Anyone for a cup of tea while we hack?!
Stevoisiak
Member
Level: 38


Posts: 96/283
EXP: 345476
For next: 24971

Since: 11-22-07

From: New York, Long Island

Since last post: 12.3 years
Last activity: 5.6 years

Posted on 07-12-08 07:19:39 PM (last edited by Stevoisiak at 07-12-08 04:23 PM) Link | Quote
Originally posted by messiaen
Stevoisiak: You're right about the different behavior. Before the star is spawned, there is an animation, so the star is not spawned right on Mario. However, keeping this behavior seems to nulify the added "Koopa" effect.


Thanks. I may barely understand any of what you guys talk about, but I'm pretty quick to figure things out. If it weren't for that ability, I'd be completely lost. Yoshimans last comment really is pushing it. (something about these behavior jumps using up space and having extra scripts be run) So I'm glad I can help.
messiaen
Catgirl
Level: 68


Posts: 231/1085
EXP: 2594041
For next: 134759

Since: 11-20-07


Since last post: 8.1 years
Last activity: 7.2 years

Posted on 08-28-08 06:01:33 PM (last edited by messiaen at 08-30-08 05:20 PM) Link | Quote
The "Show Dialog Box" function is 0x802A4BE4:

-->From the King Bob-Omb ASM:
802A7F70: ADDIU A0, R0, 0x0002 <-- Argument 0
802A7F74: ADDIU A1, R0, 0x0001 <-- Argument 1
802A7F78: ADDIU A2, R0, 0x00A2 <-- Argument 0
802A7F7C: JAL 0x802A4BE4 <-- "Show Dialog Box" Function
802A7F80: ADDIU A3, R0, 0x0080 <-- Argument 3 = Message number (80h = 128dec)
802A7F84: BEQ V0, R0, 0x802A7F9C <-- If Return = 0 do something

The first three arguments are probably the parameters discussed at the Mario 64 Dialog Params thread.

Here is an ASM Hack that get rids of hardcoded pointers/star positions in Koopa-The-Quick:

With this hack, Koopa-the-Quick (when parameter 1 = 1) won't read it's path pointer/star position from the checksum area, but will instead check for values stored in its RAM object. These values are flexible and can be set by adding these lines to Koopa's behavior:

27 3E 00 00 07 01 16 A0 [0x180 = Pointer to coordinates path]
27 3F 00 00 0B D6 11 94 [0x184 = X, Y spawned star coordinates]
27 50 00 00 EE 08 00 00 [0x1c8 = Z spawned star coordinate. Last 2 bytes are unused]

These variables seems unused by Koopa-The-Quick, so I think it's safe to use them.

Here is the original code that loads Koopa's trajectory for Bob-omb Battlefield:

802FCDF0: LUI A0, 0x8033 # A0 = 0x80330000 [Base address for memory access]
[...]
802FCDFC: ADDU A0, A0, T6 # doesn't do anything because T6 = 0
802FCE00: JAL 0x80277F50 # probably some function related with segmented memory
802FCE04: LW A0, 0x2864 (A0) # Load word from 0x80332864 (in ROM, 0xED864) [Koopa trajectory pointer]

Here is my replacement code. The last values are the instruction in machine language for easier patching.

[RAM/ROM]
802FCDF0/0xB7DF0: LUI A0, 0x8036 # A0 = 0x80360000 # Base address so we can get RAM object pointer # 3C048036
[...]
802FCDFC/0xB7DFC: LW A0, 0x1160 (A0) # Read pointer and stores at A0. # 8C841160
[...]
802FCE04/0xB7E04: LW A0, 0x0180 (A0) # Load word (Koopa's pointer) from offset 0x180 of RAM object. # 8C840180

And here's the patch for the spawned star position:

802FD658/0xB8658: LH T2, 0x01C8 (T4) # Z position # 858A01C8
802FD65C/0xB865C: LH T1, 0x0184 (T4) # X position # 85890184
802FD660/0xB8660: LH T7, 0x0186 (T4) # Y position # 858F0186
VL-Tone
Member
Super Mario 64 forum moderator
Level: 53


Posts: 248/621
EXP: 1135505
For next: 21614

Since: 07-27-07

From: Montreal, Canada

Since last post: 4.7 years
Last activity: 1.2 years

Posted on 08-31-08 04:13:24 PM Link | Quote
Time: Now - Date: Today - Weather: What can be seen outside. - Mood: How it feels. Answer to the universe: 42
This Koopa the Quick hack is really nice messiaen!

I wonder, could you make it so that you can store multiple path pointers in the same behavior script and switch between them using one of the behavior parameter?

I was thinking of doing something similar with collision pointers, so we could have "solid behaviors" containing multiple collision pointers that we could switch using a parameter. Or maybe, ideally the collision pointer would switch automatically depending on the model ID (this couldn't apply to Koopa the Quick tough since you want to use the same model ID for all paths)

BTW I'm going on vacation and will be away from home (and the net) for the next week. I should be back next week-end.

____________________
Pages: 1 2 3 Next newer thread | Next older thread
Jul - SM64 Hacking (Archive) - ASM hacking New poll - New thread - New reply


Rusted Logic

Acmlmboard - commit 47be4dc [2021-08-23]
©2000-2022 Acmlm, Xkeeper, Kaito Sinclaire, et al.

32 database queries, 15 query cache hits.
Query execution time:  0.090602 seconds
Script execution time:  0.031688 seconds
Total render time:  0.122290 seconds


TidyHTML vomit below
line 1 column 1 - Warning: missing <!DOCTYPE> declaration
line 2 column 300 - Warning: unescaped & or unknown entity "&page"
line 119 column 11 - Warning: <form> isn't allowed in <table> elements
line 118 column 10 - Info: <table> previously mentioned
line 120 column 11 - Warning: missing <tr>
line 120 column 119 - Warning: missing </font> before </td>
line 124 column 16 - Warning: plain text isn't allowed in <tr> elements
line 120 column 11 - Info: <tr> previously mentioned
line 125 column 68 - Warning: missing </nobr> before </td>
line 141 column 68 - Warning: missing </nobr> before <tr>
line 147 column 35 - Warning: missing <tr>
line 147 column 50 - Warning: missing </font> before </td>
line 148 column 37 - Warning: unescaped & or unknown entity "&id"
line 147 column 182 - Warning: missing </font> before </table>
line 149 column 35 - Warning: missing <tr>
line 149 column 96 - Warning: unescaped & or unknown entity "&page"
line 149 column 128 - Warning: unescaped & or unknown entity "&page"
line 149 column 50 - Warning: missing </font> before </td>
line 149 column 163 - Warning: missing </font> before </table>
line 156 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 158 column 9 - Warning: missing <tr>
line 176 column 13 - Warning: missing <tr>
line 177 column 99 - Warning: unescaped & or unknown entity "&postid"
line 207 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 209 column 9 - Warning: missing <tr>
line 227 column 13 - Warning: missing <tr>
line 228 column 99 - Warning: unescaped & or unknown entity "&postid"
line 232 column 170 - Warning: discarding unexpected </b>
line 232 column 103 - Warning: missing </a> before <a>
line 254 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 256 column 9 - Warning: missing <tr>
line 274 column 13 - Warning: missing <tr>
line 275 column 99 - Warning: unescaped & or unknown entity "&postid"
line 277 column 300 - Warning: missing </font> before <blockquote>
line 279 column 620 - Warning: inserting implicit <font>
line 279 column 620 - Warning: missing </font> before <hr>
line 279 column 684 - Warning: inserting implicit <font>
line 279 column 684 - Warning: missing </font> before <hr>
line 281 column 1329 - Warning: inserting implicit <font>
line 284 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 286 column 9 - Warning: missing <tr>
line 304 column 13 - Warning: missing <tr>
line 305 column 99 - Warning: unescaped & or unknown entity "&postid"
line 316 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 318 column 9 - Warning: missing <tr>
line 336 column 13 - Warning: missing <tr>
line 337 column 99 - Warning: unescaped & or unknown entity "&postid"
line 346 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 348 column 9 - Warning: missing <tr>
line 366 column 13 - Warning: missing <tr>
line 367 column 99 - Warning: unescaped & or unknown entity "&postid"
line 380 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 382 column 9 - Warning: missing <tr>
line 400 column 13 - Warning: missing <tr>
line 401 column 99 - Warning: unescaped & or unknown entity "&postid"
line 410 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 412 column 9 - Warning: missing <tr>
line 430 column 13 - Warning: missing <tr>
line 431 column 99 - Warning: unescaped & or unknown entity "&postid"
line 450 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 452 column 9 - Warning: missing <tr>
line 470 column 13 - Warning: missing <tr>
line 471 column 99 - Warning: unescaped & or unknown entity "&postid"
line 480 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 482 column 9 - Warning: missing <tr>
line 500 column 13 - Warning: missing <tr>
line 501 column 99 - Warning: unescaped & or unknown entity "&postid"
line 510 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 512 column 9 - Warning: missing <tr>
line 530 column 13 - Warning: missing <tr>
line 531 column 99 - Warning: unescaped & or unknown entity "&postid"
line 559 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 561 column 9 - Warning: missing <tr>
line 579 column 13 - Warning: missing <tr>
line 580 column 99 - Warning: unescaped & or unknown entity "&postid"
line 596 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 598 column 9 - Warning: missing <tr>
line 616 column 13 - Warning: missing <tr>
line 617 column 99 - Warning: unescaped & or unknown entity "&postid"
line 649 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 651 column 9 - Warning: missing <tr>
line 669 column 13 - Warning: missing <tr>
line 670 column 99 - Warning: unescaped & or unknown entity "&postid"
line 676 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 678 column 9 - Warning: missing <tr>
line 696 column 13 - Warning: missing <tr>
line 697 column 99 - Warning: unescaped & or unknown entity "&postid"
line 711 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 713 column 9 - Warning: missing <tr>
line 731 column 13 - Warning: missing <tr>
line 732 column 99 - Warning: unescaped & or unknown entity "&postid"
line 743 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 745 column 9 - Warning: missing <tr>
line 763 column 13 - Warning: missing <tr>
line 764 column 99 - Warning: unescaped & or unknown entity "&postid"
line 773 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 775 column 9 - Warning: missing <tr>
line 793 column 13 - Warning: missing <tr>
line 794 column 99 - Warning: unescaped & or unknown entity "&postid"
line 801 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 803 column 9 - Warning: missing <tr>
line 821 column 13 - Warning: missing <tr>
line 822 column 99 - Warning: unescaped & or unknown entity "&postid"
line 848 column 1568 - Warning: discarding unexpected </b>
line 850 column 1649 - Warning: discarding unexpected </b>
line 852 column 1842 - Warning: discarding unexpected </b>
line 858 column 2094 - Warning: discarding unexpected </b>
line 861 column 2311 - Warning: discarding unexpected </b>
line 870 column 9 - Warning: <div> isn't allowed in <table> elements
line 152 column 17 - Info: <table> previously mentioned
line 872 column 9 - Warning: missing <tr>
line 890 column 13 - Warning: missing <tr>
line 891 column 99 - Warning: unescaped & or unknown entity "&postid"
line 893 column 73 - Warning: <style> isn't allowed in <td> elements
line 893 column 9 - Info: <td> previously mentioned
line 893 column 137 - Warning: missing </div>
line 902 column 17 - Warning: missing <tr>
line 902 column 17 - Warning: discarding unexpected <table>
line 905 column 35 - Warning: missing <tr>
line 905 column 96 - Warning: unescaped & or unknown entity "&page"
line 905 column 128 - Warning: unescaped & or unknown entity "&page"
line 905 column 50 - Warning: missing </font> before </td>
line 905 column 163 - Warning: missing </font> before </table>
line 907 column 35 - Warning: missing <tr>
line 907 column 50 - Warning: missing </font> before </td>
line 908 column 37 - Warning: unescaped & or unknown entity "&id"
line 907 column 182 - Warning: missing </font> before </table>
line 909 column 17 - Warning: discarding unexpected </textarea>
line 909 column 28 - Warning: discarding unexpected </form>
line 909 column 35 - Warning: discarding unexpected </embed>
line 909 column 43 - Warning: discarding unexpected </noembed>
line 909 column 53 - Warning: discarding unexpected </noscript>
line 909 column 64 - Warning: discarding unexpected </noembed>
line 909 column 74 - Warning: discarding unexpected </embed>
line 909 column 82 - Warning: discarding unexpected </table>
line 909 column 90 - Warning: discarding unexpected </table>
line 911 column 9 - Warning: missing </font> before <table>
line 923 column 25 - Warning: discarding unexpected </font>
line 932 column 58 - Warning: discarding unexpected </font>
line 910 column 1 - Warning: missing </center>
line 120 column 63 - Warning: <img> lacks "alt" attribute
line 125 column 19 - Warning: <td> attribute "width" has invalid value "120px"
line 125 column 93 - Warning: <img> lacks "alt" attribute
line 141 column 19 - Warning: <td> attribute "width" has invalid value "120px"
line 141 column 98 - Warning: <img> lacks "alt" attribute
line 148 column 44 - Warning: <img> proprietary attribute value "absmiddle"
line 148 column 142 - Warning: <img> proprietary attribute value "absmiddle"
line 148 column 245 - Warning: <img> proprietary attribute value "absmiddle"
line 161 column 22 - Warning: <img> lacks "alt" attribute
line 161 column 63 - Warning: <img> lacks "alt" attribute
line 161 column 112 - Warning: <img> lacks "alt" attribute
line 161 column 161 - Warning: <img> lacks "alt" attribute
line 172 column 15 - Warning: <img> lacks "alt" attribute
line 212 column 22 - Warning: <img> lacks "alt" attribute
line 212 column 63 - Warning: <img> lacks "alt" attribute
line 212 column 111 - Warning: <img> lacks "alt" attribute
line 212 column 161 - Warning: <img> lacks "alt" attribute
line 223 column 15 - Warning: <img> lacks "alt" attribute
line 258 column 11 - Warning: <img> lacks "alt" attribute
line 259 column 23 - Warning: <img> lacks "alt" attribute
line 259 column 64 - Warning: <img> lacks "alt" attribute
line 259 column 113 - Warning: <img> lacks "alt" attribute
line 259 column 163 - Warning: <img> lacks "alt" attribute
line 260 column 11 - Warning: <img> lacks "alt" attribute
line 270 column 15 - Warning: <img> lacks "alt" attribute
line 281 column 1435 - Warning: <img> lacks "alt" attribute
line 289 column 22 - Warning: <img> lacks "alt" attribute
line 289 column 63 - Warning: <img> lacks "alt" attribute
line 289 column 112 - Warning: <img> lacks "alt" attribute
line 289 column 161 - Warning: <img> lacks "alt" attribute
line 300 column 15 - Warning: <img> lacks "alt" attribute
line 321 column 22 - Warning: <img> lacks "alt" attribute
line 321 column 63 - Warning: <img> lacks "alt" attribute
line 321 column 111 - Warning: <img> lacks "alt" attribute
line 321 column 161 - Warning: <img> lacks "alt" attribute
line 332 column 15 - Warning: <img> lacks "alt" attribute
line 343 column 856 - Warning: <img> proprietary attribute value "absmiddle"
line 343 column 856 - Warning: <img> lacks "alt" attribute
line 351 column 22 - Warning: <img> lacks "alt" attribute
line 351 column 63 - Warning: <img> lacks "alt" attribute
line 351 column 112 - Warning: <img> lacks "alt" attribute
line 351 column 161 - Warning: <img> lacks "alt" attribute
line 362 column 15 - Warning: <img> lacks "alt" attribute
line 385 column 22 - Warning: <img> lacks "alt" attribute
line 385 column 63 - Warning: <img> lacks "alt" attribute
line 385 column 111 - Warning: <img> lacks "alt" attribute
line 385 column 161 - Warning: <img> lacks "alt" attribute
line 396 column 15 - Warning: <img> lacks "alt" attribute
line 403 column 201 - Warning: <img> proprietary attribute value "absmiddle"
line 403 column 201 - Warning: <img> lacks "alt" attribute
line 415 column 22 - Warning: <img> lacks "alt" attribute
line 415 column 63 - Warning: <img> lacks "alt" attribute
line 415 column 112 - Warning: <img> lacks "alt" attribute
line 415 column 161 - Warning: <img> lacks "alt" attribute
line 426 column 15 - Warning: <img> lacks "alt" attribute
line 455 column 22 - Warning: <img> lacks "alt" attribute
line 455 column 63 - Warning: <img> lacks "alt" attribute
line 455 column 111 - Warning: <img> lacks "alt" attribute
line 455 column 161 - Warning: <img> lacks "alt" attribute
line 466 column 15 - Warning: <img> lacks "alt" attribute
line 485 column 22 - Warning: <img> lacks "alt" attribute
line 485 column 63 - Warning: <img> lacks "alt" attribute
line 485 column 112 - Warning: <img> lacks "alt" attribute
line 485 column 161 - Warning: <img> lacks "alt" attribute
line 496 column 15 - Warning: <img> lacks "alt" attribute
line 515 column 22 - Warning: <img> lacks "alt" attribute
line 515 column 63 - Warning: <img> lacks "alt" attribute
line 515 column 111 - Warning: <img> lacks "alt" attribute
line 515 column 161 - Warning: <img> lacks "alt" attribute
line 526 column 15 - Warning: <img> lacks "alt" attribute
line 564 column 22 - Warning: <img> lacks "alt" attribute
line 564 column 63 - Warning: <img> lacks "alt" attribute
line 564 column 112 - Warning: <img> lacks "alt" attribute
line 564 column 161 - Warning: <img> lacks "alt" attribute
line 575 column 15 - Warning: <img> lacks "alt" attribute
line 601 column 22 - Warning: <img> lacks "alt" attribute
line 601 column 63 - Warning: <img> lacks "alt" attribute
line 601 column 111 - Warning: <img> lacks "alt" attribute
line 601 column 161 - Warning: <img> lacks "alt" attribute
line 612 column 15 - Warning: <img> lacks "alt" attribute
line 619 column 163 - Warning: <img> proprietary attribute value "absmiddle"
line 619 column 163 - Warning: <img> lacks "alt" attribute
line 654 column 22 - Warning: <img> lacks "alt" attribute
line 654 column 63 - Warning: <img> lacks "alt" attribute
line 654 column 112 - Warning: <img> lacks "alt" attribute
line 654 column 162 - Warning: <img> lacks "alt" attribute
line 665 column 15 - Warning: <img> lacks "alt" attribute
line 681 column 22 - Warning: <img> lacks "alt" attribute
line 681 column 63 - Warning: <img> lacks "alt" attribute
line 681 column 112 - Warning: <img> lacks "alt" attribute
line 681 column 161 - Warning: <img> lacks "alt" attribute
line 692 column 15 - Warning: <img> lacks "alt" attribute
line 716 column 22 - Warning: <img> lacks "alt" attribute
line 716 column 63 - Warning: <img> lacks "alt" attribute
line 716 column 111 - Warning: <img> lacks "alt" attribute
line 716 column 161 - Warning: <img> lacks "alt" attribute
line 727 column 15 - Warning: <img> lacks "alt" attribute
line 748 column 22 - Warning: <img> lacks "alt" attribute
line 748 column 63 - Warning: <img> lacks "alt" attribute
line 748 column 112 - Warning: <img> lacks "alt" attribute
line 748 column 161 - Warning: <img> lacks "alt" attribute
line 759 column 15 - Warning: <img> lacks "alt" attribute
line 778 column 22 - Warning: <img> lacks "alt" attribute
line 778 column 63 - Warning: <img> lacks "alt" attribute
line 778 column 112 - Warning: <img> lacks "alt" attribute
line 778 column 162 - Warning: <img> lacks "alt" attribute
line 789 column 15 - Warning: <img> lacks "alt" attribute
line 806 column 22 - Warning: <img> lacks "alt" attribute
line 806 column 63 - Warning: <img> lacks "alt" attribute
line 806 column 111 - Warning: <img> lacks "alt" attribute
line 806 column 161 - Warning: <img> lacks "alt" attribute
line 817 column 15 - Warning: <img> lacks "alt" attribute
line 875 column 22 - Warning: <img> lacks "alt" attribute
line 875 column 63 - Warning: <img> lacks "alt" attribute
line 875 column 112 - Warning: <img> lacks "alt" attribute
line 875 column 162 - Warning: <img> lacks "alt" attribute
line 886 column 15 - Warning: <img> lacks "alt" attribute
line 893 column 693 - Warning: <img> lacks "alt" attribute
line 899 column 2386 - Warning: <img> lacks "alt" attribute
line 899 column 2545 - Warning: <img> lacks "alt" attribute
line 908 column 44 - Warning: <img> proprietary attribute value "absmiddle"
line 908 column 142 - Warning: <img> proprietary attribute value "absmiddle"
line 908 column 245 - Warning: <img> proprietary attribute value "absmiddle"
line 917 column 25 - Warning: <img> lacks "alt" attribute
line 922 column 267 - Warning: <img> lacks "alt" attribute
line 902 column 17 - Warning: trimming empty <tr>
line 125 column 68 - Warning: <nobr> is not approved by W3C
line 141 column 68 - Warning: <nobr> is not approved by W3C
line 177 column 27 - Warning: <nobr> is not approved by W3C
line 228 column 27 - Warning: <nobr> is not approved by W3C
line 275 column 27 - Warning: <nobr> is not approved by W3C
line 277 column 73 - Warning: <table> proprietary attribute "height"
line 305 column 27 - Warning: <nobr> is not approved by W3C
line 337 column 27 - Warning: <nobr> is not approved by W3C
line 367 column 27 - Warning: <nobr> is not approved by W3C
line 401 column 27 - Warning: <nobr> is not approved by W3C
line 431 column 27 - Warning: <nobr> is not approved by W3C
line 471 column 27 - Warning: <nobr> is not approved by W3C
line 501 column 27 - Warning: <nobr> is not approved by W3C
line 531 column 27 - Warning: <nobr> is not approved by W3C
line 580 column 27 - Warning: <nobr> is not approved by W3C
line 617 column 27 - Warning: <nobr> is not approved by W3C
line 670 column 27 - Warning: <nobr> is not approved by W3C
line 697 column 27 - Warning: <nobr> is not approved by W3C
line 732 column 27 - Warning: <nobr> is not approved by W3C
line 764 column 27 - Warning: <nobr> is not approved by W3C
line 794 column 27 - Warning: <nobr> is not approved by W3C
line 822 column 27 - Warning: <nobr> is not approved by W3C
line 891 column 27 - Warning: <nobr> is not approved by W3C
line 893 column 157 - Warning: <table> proprietary attribute "height"
line 893 column 222 - Warning: <td> proprietary attribute "background"
line 893 column 318 - Warning: <td> proprietary attribute "background"
line 893 column 408 - Warning: <table> proprietary attribute "height"
line 893 column 488 - Warning: <td> proprietary attribute "background"
line 893 column 1443 - Warning: <td> proprietary attribute "background"
Info: Document content looks like HTML5
Info: No system identifier in emitted doctype
Tidy found 291 warnings and 0 errors!


The alt attribute should be used to give a short description
of an image; longer descriptions should be given with the
longdesc attribute which takes a URL linked to the description.
These measures are needed for people using non-graphical browsers.

For further advice on how to make your pages accessible
see http://www.w3.org/WAI/GL.
You are recommended to use CSS to specify the font and
properties such as its size and color. This will reduce
the size of HTML files and make them easier to maintain
compared with using <FONT> elements.

You are recommended to use CSS to control line wrapping.
Use "white-space: nowrap" to inhibit wrapping in place
of inserting <NOBR>...</NOBR> into the markup.

About HTML Tidy: https://github.com/htacg/tidy-html5
Bug reports and comments: https://github.com/htacg/tidy-html5/issues
Official mailing list: https://lists.w3.org/Archives/Public/public-htacg/
Latest HTML specification: http://dev.w3.org/html5/spec-author-view/
Validate your HTML documents: http://validator.w3.org/nu/
Lobby your company to join the W3C: http://www.w3.org/Consortium

Do you speak a language other than English, or a different variant of
English? Consider helping us to localize HTML Tidy. For details please see
https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md