Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document Diablo's bugs #64

Open
ghost opened this issue Jun 24, 2018 · 165 comments · Fixed by diasurgical/devilutionX#7021
Open

Document Diablo's bugs #64

ghost opened this issue Jun 24, 2018 · 165 comments · Fixed by diasurgical/devilutionX#7021
Labels
good first issue Good for newcomers

Comments

@ghost
Copy link

ghost commented Jun 24, 2018

Currently documented bugs: The DSF Buglist for Diablo v1.09 (Lurker Lounge)

The goal of this issue is to document any new bugs we come across while examining the code that are native to the original game. This will help us fix them later on when we make mods/ports.

New bugs discovered (last update 06/24/18)

  • When casting a town portal in a quest level, leaving, and then going down into the dungon, the town portal will be placed in the dungeon. For example, Chamber of Bone is quest level 2, so the portal would appear on dungeon level 2 at the same X/Y coordinate.
  • Diablo is supposed to be immune to the squelch radius, however, the game checks the AI for Diablo's monster type, thus always failing. monster.cpp -> ProcessMonsters
@ghost ghost added the good first issue Good for newcomers label Jun 24, 2018
@fearedbliss
Copy link
Contributor

Are these bugs going to be fixed in devilution after devilution development becomes stable or is the devilution source code gonna be a pure documentation update including leaving in the vanilla bugs?

@ghost
Copy link
Author

ghost commented Jun 24, 2018

The Purpose section of the readme has the answer.

@fearedbliss
Copy link
Contributor

Ah ok, I did read this like a week ago but I guess I forgot ;D.

@ttdonovan
Copy link
Contributor

The pull request above is basically a copy of the text from the original posting with some Markup for formatting. Is something like this is what is being requested?

@ghost
Copy link
Author

ghost commented Jun 26, 2018

We can definitely make use of your copy in case the original one goes down. However, this issue is to track new bugs that haven't been documented anywhere else, so that we can fix them in the future.

(Not Devilution of course, but mods based on)

@ghost
Copy link
Author

ghost commented Jun 27, 2018

As a rule for any bug published can we have the save file for this? I would like to have something to make this more easy to replicate...

because I am thinking on looking at the TP sequence and the Chamber of bone locations... because Technically TP is working but it's not marking the chamber of bone as a different map , if I am not mistaken...

EDIT:

I am probably completely wrong on that one. The dungeon map array looks ok for the most part...

Perhaps the Portal setting and getting is wrong? Perhaps it's not specifying the correct map for special maps?

Ok . Which memory map (showing address locations) is the most accurate for the origional diablo? Do you have it ? All the addresses I am seeing appear to be inaccurate.

@ghost
Copy link
Author

ghost commented Jul 8, 2018

@ApertureSecurity check Support/surgery.xls for a spreadsheet containing addresses.

Found another one while testing the world.cpp refactor. This bug is also part of vanilla.

EDIT: This bug was Devilution only
https://s33.postimg.cc/w9y0yf6ov/doorflip.png

@ghost
Copy link
Author

ghost commented Jul 23, 2018

Brevik himself talked about this bug in an interview once. The Caves were entirely hardcoded and many fixes added per-tile:
cave bug

@ghost
Copy link
Author

ghost commented Jul 23, 2018

@galaxyhaxz is this in the origional game or are we going to add this to our bug list?

@ghost
Copy link
Author

ghost commented Sep 10, 2018

Well, it looks like the door issue mentioned above was devilution specific. However, these pieces are saved with the character so it becomes bugged when loading the character in a vanilla game. ee56751

@mewmew
Copy link
Contributor

mewmew commented Sep 10, 2018

Well, it looks like the door issue mentioned above was devilution specific. However, these pieces are saved with the character so it becomes bugged when loading the character in a vanilla game. ee56751

Interesting find. This is good to know when validating bugs in the future against vanilla Diablo. Basically, we can use the same seed for dungeon generation when validation, but we can't use save files.

@ghost
Copy link
Author

ghost commented Sep 12, 2018

There is an overflow bug in the dungeon algorithm of Cathedral that sometimes causes out-of-map pieces. Documented here.

I can confirm that Devilution works correctly (i.e. is bugged like vanilla). Current known seeds:

Cathedral:
2588
4743
7281
9345
15236

@ghost
Copy link
Author

ghost commented Nov 1, 2018

Eldritch Shrine Bug

The Eldritch shrine (turns healing/mana pots into rejuvs and full pots into full rejuvs) uses the player's holding item buffer to temporarily store the rejuvs. What could possibly go wrong here?........ xD xD

If you click on the shrine and then pickup an item from your inventory/belt, the item you're holding will get overwritten. When you place it back down, it turns into a rejuv. BEWARE!

As a side note, this can be exploited for an extra rejuv, grabbing say 1 piece of gold or some junk item.

Bugfix

The routine for this in OperateShrine should use a temporary buffer local to the function or the global temporary buffer curruitem to fix this. :)

@mewmew
Copy link
Contributor

mewmew commented Nov 1, 2018

As a side note, this can be exploited for an extra rejuv, grabbing say 1 piece of gold or some junk item.

Haha, great hack!

@ghost
Copy link
Author

ghost commented Mar 17, 2019

Edit: actually the spaces in yellow are spots where there aren't any pixels in the .CEL, so the game never draws anything there. The function responsible for drawing the void fills them black. The only way to fix this is to edit the CEL map and create pixels in the empty spots.
DIABLO_2019031337_061641
DIABLO_20190317_221850

@ghost
Copy link
Author

ghost commented Apr 4, 2019

By chance I stumbled upon a broken tile on level 5. Here is the picture with seed and location:
_seed_bug_lv5

@mewmew
Copy link
Contributor

mewmew commented Apr 5, 2019

It's great. We are gonna be able to create a version of Diablo that fixes all known bugs. Of course, Devilution will contain all original bugs to stay true to its origin.

@ghost
Copy link
Author

ghost commented Apr 7, 2019

Another bug where standing in certain spots overwrites the top left corner of the control panel:
_tile_bug_lv1

@mewmew
Copy link
Contributor

mewmew commented Apr 7, 2019

Another bug where standing in certain spots overwrites the top left corner of the control panel:

Is this in vanilla too? Never seen the panel being incorrectly rendered before.

@AJenbo
Copy link
Member

AJenbo commented Apr 7, 2019

All your belt items also went invisible. Could be a miss calculated CelSkip/CelCap

@ghost
Copy link
Author

ghost commented Apr 7, 2019

@mewmew Yeah it's in vanilla. You won't notice the bug unless you hover your mouse over that spot in the control panel, it overwrites the panel graphic. I rewrote the whole render and discovered this bug while testing. It's likely caused by DrawMain not blitting all parts of the screen all the time.

@AJenbo The belt items is just a side effect of the new render, not in vanilla. If you notice there's transparency! <3

Edit: attached save file so you can test it. Load the game and place mouse over top left corner.
single_4.zip

Interesting is that this bug doesn't happen in the debug release or prior. So it was caused by something changed in the render in 1.00.

@ghost
Copy link
Author

ghost commented Apr 28, 2019

@AJenbo had pointed this bug out awhile back, as it was thought to be caused by my render re-implementation. Actually, it's caused by the whole eflag system where for some reason, when walking south east, arches aren't drawn above the player. So the fix was to add separate drawing code outside of the render. I had to catch it mid action, but the spots in yellow are where eflag tiles are drawn. They overwrite the book case. IIRC this bug was fixed in the PSX version, since they ditched eflag entirely.
DIABLO_20190428_063210

@AJenbo
Copy link
Member

AJenbo commented Apr 28, 2019

Nice catch, my print screen has a delay so getting shots like this is a pain :)

The other yellow box is causing issues when we upgrade the render to have per-pixel transparency because it renders the tile twice, resulting in 75% opaqueness instead of 50%

@AJenbo
Copy link
Member

AJenbo commented May 16, 2019

Here's another render issue:
Caves

diasurgical/devilutionX#111

@qndel
Copy link
Member

qndel commented May 16, 2019

In the very tristram itself :)
image

Zoomed:
image

I'ts more obvious in tchernobog, that's what made me notice it :P

@ghost
Copy link
Author

ghost commented May 16, 2019

@AJenbo I believe that issue is the same one I reported above. There's a broken tile that can occasionally spawn in the caves that does that.

Here is a list of seeds for Caves with that broken tile and the coordinate of it:

seed 24, x 28, y 10
seed 206, x 19, y 27
seed 265, x 27, y 6
seed 534, x 26, y 20
seed 1714, x 24, y 25
seed 1980, x 12, y 14

Here is code to fix the tile by brute force. It should be ran during DRLG_L3:

	for(j = 0; j < 40; j++)
	{
		for(i = 0; i < 40; i++)
		{
			if(dungeon[i][j] == 9 && dungeon[i - 1][j] == 13 && dungeon[i][j - 1] == 14)
			{
				dungeon[i][j] = 7; // set broken tiles to dirt instead of stalagmite
				dungeon[i][j - 1] = 7;
				dungeon[i-1][j] = 7;
			}
		}
	}

Additionally, here are seeds for Catacombs that contain the broken wall tile:

550
2346
2377
2992
5162
6365
6500
6711
7152
7155
7462

And the code to fix it:

			if(dungeon[i][j] == 15 && dungeon[i][j + 1] == 1) { /// add this check
				dungeon[i][j + 1] = 8; // change left wall to left corner
			}

Last but not least, some more seeds with the overflow bug in DRLG_L1 documented by @mewmew:

24627
29946
32559

@k-bar
Copy link

k-bar commented Jun 6, 2022

As this issue also lists not only Diablo, but Hellfire bugs too:
berserkRangedBad

Berserked (ranged) monster missile will always miss another not-berserked monster
diasurgical/devilutionX#4669

@k-bar
Copy link

k-bar commented Jun 6, 2022

Hellfire: Berserked monsters hit won't wake up other melee monsters
berserkWakeMeleeBad
(same for missiles, but it is broken that won't even hit.)
diasurgical/devilutionX#4670

@ephphatha
Copy link

In multiplayer games trapped doors get reset and can be triggered twice if the door is closed when a player enters the level.

SyncOp*Door return early if the door state is closed and the latest command in the delta for that object is a CLOSEDOOR command, which doesn't clear the trap flag. The code that syncs trap state then sees the door is closed and doesn't register it's been tripped.

diasurgical/devilutionX#5184

@qndel
Copy link
Member

qndel commented Aug 7, 2022

Talking to any NPC while help is being displayed will cause the npc panel to mix with it and stay broken even after closing help (can't interact with it)
diasurgical/devilutionX#5208

image
image

@qndel
Copy link
Member

qndel commented Aug 16, 2022

diasurgical/devilutionX#5248
You can overwrite cursor items if you cast a cursor changing spell right before picking an item to cursor (the opposite of duping :D)

@mewmew
Copy link
Contributor

mewmew commented Sep 21, 2022

drlg_l2: Certain seeds cause dungeon generation to get stuck in an infinite loop. (see diasurgical/devilutionX#5346; reported by @kpyrkosz)

Analysis of bug by @AJenbo

ref: diasurgical/devilutionX#5346 (comment)

The issue here is that it fails to connect two doors, walking in the opposite direction, hitting a wall and not turning around.

beginning 22x10, end 10x12, dir: 3

                                         
                                         
                                         
                                         
                                         
                                         
                                         
                                 C##E    
                         C###E   #..#    
             C#####E     #...#   #..#    
            ,D.....#     #...#   #..#    
             #.....#     #...#   B##A    
             #.....#     #...#           
             #.....#     #...#           
             B##D##A     #...#           
               ,,,       B###A           
               ,,,                       
               ,,,     C#######E         
               ,,,     #.......#         
               ,,,     #.......#         
               ,,,     #.......#         
       C###E   ,,,     B#######A         
       #...D   CDE                       
       #...#   #.#                       
       #...#   #.#                       
       B###A   #.#         C#######E     
               #.#         #.......#     
               BDA         #.......#     
                ,          #.......#     
               ,,,         #.......#     
                ,          #.......#     
            C###D####E     #.......#     
            #........#     #.......#     
      C###E #........#     #.......#     
      #...# #........#     B#######A     
      #...# #........#                   
      #...# #........#                   
      B###A #........#                   
            B########A                   
                                         

After 1600 iterations:

                                         
                                         
                                         
                                         
                                         
                                         
                                         
                                 C##E    
                         C###E   #..#    
             C#####E     #...#   #..#    
            ,D.....#     #...#   #..#    
             #.....#     #...#   B##A    
             #.....#     #...#           
             #.....#     #...#           
             B##D##A     #...#           
               ,,,       B###A           
               ,,,                       
               ,,,     C#######E         
               ,,,     #.......#         
               ,,,     #.......#         
               ,,,     #.......#         
       C###E   ,,,     B#######A         
       #...D,  CDE                       
       #...#,  #.#                       
       #...#,  #.#                       
       B###A,  #.#         C#######E     
            ,  #.#         #.......#     
            ,  BDA         #.......#     
            ,   ,          #.......#     
            ,  ,,,         #.......#     
            ,   ,          #.......#     
            C###D####E     #.......#     
            #........#     #.......#     
      C###E #........#     #.......#     
      #...# #........#     B#######A     
      #...# #........#                   
      #...# #........#                   
      B###A #........#                   
            B########A                   
                               

@mewmew
Copy link
Contributor

mewmew commented Nov 17, 2022

Solitary pillar in drlg_l2 dungeon generation.

From diasurgical/devilutionX#5432:

solitary pillar

@galaxyhaxz
Copy link
Member

galaxyhaxz commented Jan 3, 2023

Everyone loves item bugs, so here's a few I just fixed after much pondering:

  • Fleshstinger: It has increase durability by 6%. They clearly intended to set the durability to 6 instead. The same bug appeared on Split Skull Shield in the demo, which they fixed by using 15 instead (6 would be too low).
  • Hammer of Jholm: It has +4-10% (varies) enhanced damage. This has no effect on the weapon since it is too low, but the unique item has a qlvl of 1. It seems more likely they meant to set the actual damage to 4-10 to make it weaker, but since mauls don't drop from level 1 monsters, it makes it useless. (Hence the reason this item has weak stats)
  • Stormshield: It's missing the lightning resist (in both demo+Diablo 2). They removed it to use the slot for changing the graphic.

@galaxyhaxz
Copy link
Member

galaxyhaxz commented Jan 11, 2023

I found an exploit created by the negative stat shrines. First, let's lay down a few rules:

  • Ornate, Sacred, and Fascinating shrines reduce mana by 10%. Sets mana to 0 if negative.
  • Mysterious shrine and Tear fountain remove 1 to a random stat.
  • When game saves, stat values are stored as unsigned.

This trick works best with a level 1 Warrior. If you hit enough shrines to get your magic reduced to -1, then start a new game, it will be 255 since the value is unsigned. If you click any item it will refresh back to 50 however. The idea is you get a bunch of books for spells you cannot learn, get your magic down to -1, make a new game and use the books as this will not reset the stat. You then have to reduce your magic all over again back to 0 this time, hit the shrines to set your mana to zero, then drink elixirs to get mana again.

For strength and dexterity which don't have stat effects, it works even better. On a level 1 warrior, you could save/load before the random stat shrines and keep hitting until you get them to -1, make a new game, then they will be maxed out!

@ikonomov
Copy link

ikonomov commented Jan 28, 2023

There is formula for the damage of Guardian which is not being used and the damage of Firebolt is used instead:

missile[mi]._midam = random_(62, 10) + (plr[id]._pLevel >> 1) + 1;

@ephphatha
Copy link

The hit detection to determine which area of the inventory (or belt) is under the mouse cursor doesn't align with the panel graphics particularly well.

In the following image the green areas are base hit regions, depending on the action being performed an extra line of pixels above (and sometimes to the right) of these areas is also included.
2023-03-25T154617_devilutionx_markup

Using the left ring slot as an example rings are drawn as a 28x28 pixel sprite with the lower left corner at (48, 205) relative to the top left corner of the panel. The hit area is a 28x29 (when pasting an item) or 29x29 (when picking up an item) region with the lower left corner at (45, 205). The area inside the golden border visible in the panel UI is 28x29 pixels with the lower left corner at (47, 206).

The gap between columns in the left/right hand slots means that it's possible to pick up a weapon/shield and not be able to place it back down again unless you move the mouse one pixel left or right. This also happens with the gutters between columns of the inventory for items two tiles wide.

@AJenbo
Copy link
Member

AJenbo commented Apr 16, 2023

Click an NPC, while walking to them click and hold down the inv button. Once the NPC interaction starts let go of the inv button.
You will now have an unresponsive inventory UI on top of the NPC UI.

@StephenCWills
Copy link
Member

StephenCWills commented May 4, 2023

Rampant use of SetRndSeed() using the absolute value of RNG state breaks the flow of the RNG sequence and screws up the uniformity of the random number generator. You can see this demonstrated in Griswold's premium item generation algorithm. We discovered a rather small closed loop in that algorithm that produces just ten Hellfire items. By seeding the RNG just right and carrying a bunch of expensive gear in your inventory, you can force the shop to display the same item in every one of the shop's slots.

image

The attached file below contains debug output where I traced the calls to the RNG functions in DevilutionX. The functions in DevilutionX are more or less just renamed from the original functions in Devilution.

  • AdvanceRndSeed() = GetRndSeed()
  • SetRndSeed() = SetRndSeed()
  • GenerateRnd() = random_()

hellfire-rng-closed-loop.txt

The most obvious solution to this would be to use the unmodified RNG state when capturing a seed to be used later. However, it would also make some sense to implement the ability to instance the RNG so you can generate a specific item or object's random number sequence without disturbing the random number sequence of, say, the RNG used for game mechanics.

@StephenCWills
Copy link
Member

Because the game captures random numbers to be used later as seeds for the RNG, it's possible for two chests on the same dungeon level to produce duplicate items. The conditions for the simplest and most likely way for this to happen are outlined below.

  • The chest must drop at least two items.
  • The next chest that was placed must drop at least one item.
  • The RNG state must have been a positive integer when capturing the seed for the chest object.
  • The RNG state must have been a positive integer when capturing the seed for the next chest object that was placed.
  • The RNG state must be a positive integer when capturing the seed for the first item from the chest.
  • The "RNG distance" between the chest's seed and the next chest's seed must be the same as the number of random numbers used to generate the first item.

If the stars align, RNG state after generating the chest's first item will be identical to the seed for the chest that was placed after it. I captured the following output from Devilution using glSeedTbl[1] = 312 and opening the chests at object[87] and object[86]. In this example, the game had generated a duplicate gold pile with seed 1292792715.

Operating chest 87
SetRndSeed(-1271890865 -> 23863461)
random_(100) >> GetRndSeed(23863461 -> 1549207594)
random_(15) >> GetRndSeed(1549207594 -> -1421509453)
GetRndSeed(-1421509453 -> 726620944) returns 726620944
SetRndSeed(726620944 -> 726620944)
random_(1) >> GetRndSeed(726620944 -> 952941137)
random_(10) >> GetRndSeed(952941137 -> -190758714)
random_(100) >> GetRndSeed(-190758714 -> 1387969791)
random_(100) >> GetRndSeed(1387969791 -> 1994707660)
[CreateRndItem] Gold (726620944)

random_(100) >> GetRndSeed(1994707660 -> 1028770877)
random_(15) >> GetRndSeed(1028770877 -> -1466179934)
GetRndSeed(-1466179934 -> 1292792715) returns 1292792715
SetRndSeed(1292792715 -> 1292792715)
random_(1) >> GetRndSeed(1292792715 -> -2062531128)
random_(10) >> GetRndSeed(-2062531128 -> -772709783)
random_(100) >> GetRndSeed(-772709783 -> 81747390)
random_(100) >> GetRndSeed(81747390 -> -1013298089)
[CreateRndItem] Gold (1292792715)
Operating chest 86
SetRndSeed(-1013298089 -> 1994707660)
random_(100) >> GetRndSeed(1994707660 -> 1028770877)
random_(15) >> GetRndSeed(1028770877 -> -1466179934)
GetRndSeed(-1466179934 -> 1292792715) returns 1292792715
SetRndSeed(1292792715 -> 1292792715)
random_(1) >> GetRndSeed(1292792715 -> -2062531128)
random_(10) >> GetRndSeed(-2062531128 -> -772709783)
random_(100) >> GetRndSeed(-772709783 -> 81747390)
random_(100) >> GetRndSeed(81747390 -> -1013298089)
[CreateRndItem] Gold (1292792715)

I believe in this case, the safest solution would be to "create space" in the random number sequence by burning random numbers after capturing the object seed. The number of random numbers burned should be determined based on the expected number of random numbers it would take to generate the items from the chest. Then the burned numbers would be used exclusively for generating the items from the chest, forcing the next chest to be seeded using a random number later in the sequence.

@ikonomov
Copy link

ikonomov commented Jul 6, 2023

Cursed items with low price value can't be repaired:

Untitled-1

@qndel
Copy link
Member

qndel commented Jul 23, 2023

2 hellfire bugs:
special dmg case (has both lightning and fire dmg) - melee and missiles - was dealing dmg between min / (max-1) range instead of min/max

placing nakrul lever uses a loop for finding a random spot for it then discards the results and forces it to be in front of his room anyway - as @galaxyhaxz suggested, probably leftover from dev testing - they forced it to spawn in front of his room so they wouldn't have to look for it :D

@ephphatha
Copy link

The RNG bug described in diasurgical/devilutionX#2206 leads to some odd interactions if you happen to be unlucky enough to get the 1 in 4 billion value at key points.

Griswold can spawn with a shop that only offers two normal items:
2023-09-19T212034_devilutionx

This also can happen with Pepin and (if playing in Hellfire) Adria. Pepin will only offer the potions he always sells (will not offer any scrolls or elixirs), Adria will only offer books.

Another possible effect is repairing a staff can instead consume all charges, causing the max charges to be completely depleted at the same time. This is much harder to trigger as you not only need to get the bad roll but you need to have a combination of player level and staff spell level so that the maximum recharge amount (plevel / slevel) is not a power of two.

Certain oils could give less of a bonus than expected (Oil of Mastery, Oil of Skill, Oil of Fortitude, Oil of Imperviousness)

Hell levels could have a visual glitch due to a bad substitution where a piece of bone embedded in the ground is used on one tile instead of a bone spur sticking up.

@qndel
Copy link
Member

qndel commented Oct 24, 2023

diasurgical/devilutionX#6661
Some bosspack bugs:

Scavengers leave the pack while feeding but never rejoin it:
leaderflag values: 0 (none), 1 (leashed), 2 (separated)

Feeding scavengers checked for nonzero values and overwrote leaderflag to 0, while GroupUnity only makes monsters with flag 2 rejoin packs = scavengers after feeding didn't have a way to rejoin pack.

Stone curse broke packs hard - if you stoned any monster, whole pack would wait for it = stuck.
Stone curse and kill a monster and pack is stuck forever.

@mewmew
Copy link
Contributor

mewmew commented Oct 24, 2023

Stone curse broke packs hard - if you stoned any monster, whole pack would wait for it = stuck.
Stone curse and kill a monster and pack is stuck forever.

I'd call that a feature in my book.

@galaxyhaxz
Copy link
Member

Stone curse and kill a monster and pack is stuck forever.

Technically, only the leader is broke as he waits to sync all pack members and will idle until you are close. The members will still attack, but will not go farther than his radius.

Scavengers leave the pack while feeding but never rejoin it:

You be the judge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

Successfully merging a pull request may close this issue.