Smashing rocks has a chance to contain items - pret/pokecrystal GitHub Wiki

In HGSS, XY and ORAS, it is possible to use Rock Smash and instead of encountering a Pokémon (or nothing...), you could also find an item from a small table of potential item drops.

This tutorial will go over how to achieve that functionality in pokecrystal. (This feature was adapted from Polished Crystal: huge thanks to Rangi!)

Contents

  1. Modifying the overworld functionality
  2. Adding the rock item code

1. Modifying the overworld functionality

First, we must edit the RockSmashScript within engine/events/overworld.asm:

	callasm RockMonEncounter
	readmem wTempWildMonSpecies
-	iffalse .done
+	iffalse .no_battle
	randomwildmon
	startbattle
	reloadmapafterbattle
-.done
	end

+.no_battle
+	callasm RockItemEncounter
+	iffalse .no_item
+	opentext
+	verbosegiveitem ITEM_FROM_MEM
+	closetext
+.no_item
+	end

These changes stop the RockSmashScript from ending if it doesn't find a Pokémon, jumping to .no_battle in that case, and then calling RockItemEncounter to determine whether or not an item will be found under the rock. If no item is selected, the script will jump to .no_item, ending the script and giving the player nothing.

But RockItemEncounter has yet to be defined, so these changes on their own will not work.

2. Adding the rock item code

We have to define RockItemEncounter, and a suitable place to put it would be in engine/events/checkforhiddenitems.asm at the bottom of the script:

.GetFarByte:
	ld a, [wBuffer1]
	call GetFarByte
	inc hl
	ret
+
+RockItemEncounter:
+	ld hl, .RockItems
+	call Random
+.loop
+	sub [hl]
+	jr c, .ok
+	inc hl
+	inc hl
+	jr .loop
+
+.ok
+	ld a, [hli]
+	inc a
+	jr z, .done
+	ld a, [hli]
+.done
+	ld [wScriptVar], a
+	ret
+	
+.RockItems:
+	db 1, MAX_REVIVE
+	db 2, THICK_CLUB
+	db 4, NUGGET
+	db 6, STAR_PIECE
+	db 12, BIG_PEARL
+	db 18, ETHER
+	db 24, HARD_STONE
+	db 24, SOFT_SAND
+	db 48, PEARL
+	db 64, BRICK_PIECE
+	db -1

For starters, RockItemEncounter will load the .RockItems table into hl, and then call Random, which will load a random byte (i.e., a value between 0 and 255) in a. With this random value generated, it performs comparisons against the probabilities encoded in the .RockItems table, picking an item with the listed odds (out of 256: in the example, there's a 1 in 256 chance of getting a Max Revive, and a 64 in 256 (or 1 in 4) chance of getting a Brick Piece). Since the probabilities in the table add up to less than 256, the db -1 line at the end indicates the end of the table. If this line is reached, the function will load a 0 (which represents NO_ITEM), indicating that the rocks didn't contain an item. If this is the case, the iffalse .no_item line in the script will skip giving an item to the player. Otherwise, the selected item, which will have already been loaded into the script variable (wScriptVar) by the function, will be awarded to the player by the script.

And there you have it, the player can now find items within smashed rocks! You can add your own items and chances by editing the .RockItems table in checkhiddenitems.asm, or even add something more complex like the Fossils/Old Amber from RBY.

Note that the probabilities can only add up to 256 or less. (If they add up to 256 exactly, the final db -1 is not needed, but it can be left in place just in case.) If they add up to more than 256, the last entries in the table will be inaccessible.

Screenshot