Jump to content

Pickpocket exploits (several)


CamDawg

Recommended Posts

You could pickpocket the beljuril from the Imensvale chicken, tear of Bhaal from the hell trials genie, and the Ring of Gaxx from Kangaxx's lich form. BD's solution was to move them to item slots that are unpickpocketable (such as gloves and whatnot); I'm just adding the unstealable flag.

 

// makes beljuril un-pickpocketable from chicken
COPY_EXISTING ~gemch02.cre~ ~override~
 READ_LONG 0x2bc "itm_off"
 READ_LONG 0x2b0 "itm_num"
 WHILE ("%itm_num%" > 0) BEGIN
   SET "itm_num" = ("%itm_num%" - 1)
   READ_ASCII ("%itm_off%" + (0x14 * "%itm_num%")) "item"
   PATCH_IF ("%item%" STRING_COMPARE_CASE "misc6z" = 0) BEGIN
     READ_BYTE  ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) "flags"
     WRITE_BYTE ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) ("%flags%" BOR 0b00000010)
   END
 END
 IF ~CRE~
 BUT_ONLY_IF_IT_CHANGES
 
// makes tear of bhaal un-pickpocketable from hell trial genie
COPY_EXISTING ~hellgen.cre~ ~override~
 READ_LONG 0x2bc "itm_off"
 READ_LONG 0x2b0 "itm_num"
 WHILE ("%itm_num%" > 0) BEGIN
   SET "itm_num" = ("%itm_num%" - 1)
   READ_ASCII ("%itm_off%" + (0x14 * "%itm_num%")) "item"
   PATCH_IF ("%item%" STRING_COMPARE_CASE "miscb7" = 0) BEGIN
     READ_BYTE  ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) "flags"
     WRITE_BYTE ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) ("%flags%" BOR 0b00000010)
   END
 END
 IF ~CRE~
 BUT_ONLY_IF_IT_CHANGES

// makes kangaxx-the-lich's ring un-pickpocketable and undroppable
COPY_EXISTING ~hellgen.cre~ ~override~
 READ_LONG 0x2bc "itm_off"
 READ_LONG 0x2b0 "itm_num"
 WHILE ("%itm_num%" > 0) BEGIN
   SET "itm_num" = ("%itm_num%" - 1)
   READ_ASCII ("%itm_off%" + (0x14 * "%itm_num%")) "item"
   PATCH_IF ("%item%" STRING_COMPARE_CASE "ring39" = 0) BEGIN
     READ_BYTE  ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) "flags"
     WRITE_BYTE ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) ("%flags%" BOR 0b00001010)
   END
 END
 IF ~CRE~
 BUT_ONLY_IF_IT_CHANGES

Link to comment

Another item not unpickpocketable:

 

// Makes Helm of Glory unpickpocketable
COPY_EXISTING ~sctelwyn.cre~ ~override~
READ_LONG 0x2bc "itm_off"
READ_LONG 0x2c0 "itm_num"
WHILE ("%itm_num%" > 0) BEGIN
  SET "itm_num" = ("%itm_num%" - 1)
  READ_ASCII ("%itm_off%" + (0x14 * "%itm_num%")) "item"
  PATCH_IF ("%item%" STRING_COMPARE_CASE "helm03" = 0) BEGIN
    READ_BYTE  ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) "flags"
    WRITE_BYTE ("%itm_off%" + 0x10 + (0x14 * "%itm_num%")) ("%flags%" BOR 0b00000010)
  END
END
IF ~CRE~
BUT_ONLY_IF_IT_CHANGES

Link to comment

Is this the right thing to do? If the unstealable flag is never cleared, then it will never be possible to steal the item from anyone. While I can't imagine this would ever cause a real-world issue (maybe in multiplayer?), it gives me that icky feeling.

Link to comment

Shit, I didn't even think about it. The unstealable flag does persist, so we need to move the items around instead. This will search for the item in question in inventory slots and move it to the first available equipment slot, starting with the quick slots and moving up.

 

This one fix now handles all of the above, plus two more fixes: the ihtafeer's head in the druid grove, and the Sahuagin prince's blood.

 

// eliminates pickpocket exploits
COPY_EXISTING ~gemch02.cre~  ~override~
             ~hlkang.cre~   ~override~
             ~hellgen.cre~  ~override~
             ~sctelwyn.cre~ ~override~
             ~trrak01.cre~  ~override~
             ~udprince.cre~ ~override~
 READ_LONG 0x2b8 "slot_off"
 READ_LONG 0x2bc "itm_off"
 READ_LONG 0x2c0 "itm_num"
 SET "hide" = 16
 SET "seek" = 0
 WHILE ("%itm_num%" > 0) BEGIN
   SET "itm_num" = ("%itm_num%" - 1)
   READ_ASCII ("%itm_off%" + (0x14 * "%itm_num%")) "item"
   PATCH_IF (("%item%" STRING_COMPARE_CASE "misc6z" = 0) AND ("gemch02.cre" STRING_COMPARE_CASE ~%SOURCE_FILE%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // beljuril from chicked
   END
   PATCH_IF (("%item%" STRING_COMPARE_CASE "miscb7" = 0) AND ("hellgen.cre" STRING_COMPARE_CASE ~%SOURCE_FILE%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // tear of bhaal from hell genie
   END
   PATCH_IF (("%item%" STRING_COMPARE_CASE "ring39" = 0) AND ("hlkang.cre" STRING_COMPARE_CASE ~%SOURCE_FILE%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // ring of gaxx from kangaxx
   END
   PATCH_IF (("%item%" STRING_COMPARE_CASE "helm03" = 0) AND ("sctelwyn.cre" STRING_COMPARE_CASE ~%SOURCE_FILE%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // helm of glory from telwyn
   END
   PATCH_IF (("%item%" STRING_COMPARE_CASE "misc8k" = 0) AND ("trrak01.cre" STRING_COMPARE_CASE ~%SOURCE_FILE%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // ihtafeer's head
   END
   PATCH_IF (("%item%" STRING_COMPARE_CASE "misca7" = 0) AND ("udprince.cre" STRING_COMPARE_CASE ~%SOURCE_FILE%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // sahuagin prince's blood
   END
 END
 WHILE ("%hide%" > 0) BEGIN // search through inventory and remove references
   SET "hide" = ("%hide%" - 1)
   READ_SHORT ("%slot_offset%" + 0x2a + ("%hide%" * 0x02) "ref"
   PATCH_IF ("%ref%" = "%slot%") BEGIN // if item found
     WRITE_SHORT ("%slot_offset%" + ("%hide%" * 0x02) 0xffff // negative one, null reference
     SET "hide" = 0  // kills loop
     SET "seek" = 21 // sets value to initiate placement loop
   END
 END
 WHILE ("%seek%" > 0) BEGIN // search through equipment and add reference to first null slot
   SET "seek" = ("%seek%" - 1)
   READ_SHORT ("%slot_offset%" + ("%seek%" * 0x02) "ref"
   PATCH_IF ("%ref%" < 0) BEGIN // first null reference
     WRITE_SHORT ("%slot_offset%" + ("%seek%" * 0x02) "%slot%" // adds reference to item
     SET "seek" = 0 // kills loop
   END
 END
 BUT_ONLY_IF_IT_CHANGES

Link to comment
Is this the right thing to do? If the unstealable flag is never cleared, then it will never be possible to steal the item from anyone. While I can't imagine this would ever cause a real-world issue (maybe in multiplayer?), it gives me that icky feeling.

You probably know more about this but me, but we're not changing the item-flag, but rather the flag in the creature. But maybe that doesn't make any difference?

Link to comment

That was my first thought as well, but it turns out it doesn't matter; I tested this ingame. I created gemch02, and the beljuril was not pickpocketable. However, after killing the chicken and giving the beljuril to Minsc, I could not pickpocket it from him either. This was true whether he was in or out of the party.

Link to comment
but rather the flag in the creature
For posterity, these are most likely override flags. When the engine populates the object with the referenced items, it applies the flags (in addition to the charges) to the base items as they're created. This is a good thing, otherwise you'd need separate item files for every possible variation of charge and flag. The downside is that the flags are persistent (just as the number of charges are).

 

As for the revised patch, I would absolutely suggest that you use PATCH_IF (expression) BEGIN (patch) END ELSE PATCH_IF (expression) BEGIN ... -- this will speed up operation, as you're only evaluating the minimum number of expressions (with if-else, the "else" conditions are only checked if the parent "if" conditions are false). This way, you're checking at minimum one single expression, and at maximum the full six expressions, with most falling in the middle (2-5). For such a small number of files, this won't make too much difference, but it can really speed things up when you're processing lots of files (or have a huge patch list).

Link to comment

Included in alpha 3, with devSin's superior code recommendations. :)

 

// eliminates pickpocket exploits
COPY_EXISTING ~gemch02.cre~  ~override~
             ~hellgen.cre~  ~override~
             ~hlkang.cre~   ~override~
             ~sctelwyn.cre~ ~override~
             ~trrak01.cre~  ~override~
             ~udprince.cre~ ~override~
 READ_LONG 0x2b8 "slot_off"
 READ_LONG 0x2bc "itm_off"
 READ_LONG 0x2c0 "itm_num"
 SET "hide" = 0
 SET "seek" = 0
 WHILE ("%itm_num%" > 0) BEGIN
   SET "itm_num" = ("%itm_num%" - 1)
   READ_ASCII ("%itm_off%" + (0x14 * "%itm_num%")) "item"
   PATCH_IF (("%item%" STRING_COMPARE_CASE "misc6z" = 0) AND ("gemch02" STRING_COMPARE_CASE ~%SOURCE_RES%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // beljuril from chicked
   END ELSE
   PATCH_IF (("%item%" STRING_COMPARE_CASE "miscb7" = 0) AND ("hellgen" STRING_COMPARE_CASE ~%SOURCE_RES%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // tear of bhaal from hell genie
   END ELSE
   PATCH_IF (("%item%" STRING_COMPARE_CASE "ring39" = 0) AND ("hlkang" STRING_COMPARE_CASE ~%SOURCE_RES%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // ring of gaxx from kangaxx
   END ELSE
   PATCH_IF (("%item%" STRING_COMPARE_CASE "helm03" = 0) AND ("sctelwyn" STRING_COMPARE_CASE ~%SOURCE_RES%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // helm of glory from telwyn
   END ELSE
   PATCH_IF (("%item%" STRING_COMPARE_CASE "misc8k" = 0) AND ("trrak01" STRING_COMPARE_CASE ~%SOURCE_RES%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // ihtafeer's head
   END ELSE
   PATCH_IF (("%item%" STRING_COMPARE_CASE "misca7" = 0) AND ("udprince" STRING_COMPARE_CASE ~%SOURCE_RES%~ = 0)) BEGIN
     SET "slot" = "%itm_num%" // sahuagin prince's blood
   END
 END
 WHILE ("%hide%" < 16) BEGIN // search through inventory and remove references
   READ_SHORT ("%slot_off%" + 0x2a + ("%hide%" * 0x02)) "ref"
   PATCH_IF ("%ref%" = "%slot%") BEGIN // if item found
     WRITE_SHORT ("%slot_off%" + 0x2a + ("%hide%" * 0x02)) 0xffff // negative one, null reference
     SET "hide" = 0  // kills loop
     SET "seek" = 21 // sets value to initiate placement loop
   END
   SET "hide" = ("%hide%" + 1)
 END
 WHILE ("%seek%" > 0) BEGIN // search through equipment and add reference to first null slot
   SET "seek" = ("%seek%" - 1)
   READ_SHORT ("%slot_off%" + ("%seek%" * 0x02)) "ref"
   PATCH_IF ("%ref%" = 0xffff) BEGIN // first null reference
     WRITE_SHORT ("%slot_off%" + ("%seek%" * 0x02)) "%slot%" // adds reference to item
     SET "seek" = 0 // kills loop
   END
 END
 BUT_ONLY_IF_IT_CHANGES

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...