Jump to content


Photo

Revised Thievery addition - [IMPLEMENTED]


  • Please log in to reply
53 replies to this topic

#21 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 11 May 2009 - 06:48 AM

Cheers, mate. I pretty much pinched this wholesale, if you don't mind :D.


Not at all. :) As long as your file names and variables don't contain the RR# prefix, feel free to use (and modify) the scripts and dialogue involved in that component for your own mod.

Sure, a lot of people might get violent if pickpocketed, but it's unlikely a lowly merchant with any sense would try to take on a fully armored party.


I'm afraid that's hardcoded. A failed pickpocket attempt is treated as an attack by the engine.

#22 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 18 May 2009 - 03:26 AM

A failed pickpocket attempt is treated as an attack by the engine.

Not anymore. "The hardcodedness is no bar to our hackery."
BACKUP ~picking/backup~
AUTHOR ~Taimon and Miloch~

BEGIN ~Pickpocketing Patch~

COPY ~BGMain.exe~ ~BGMain.exe~
  READ_BYTE 0x5438c3 p1
  READ_LONG 0x5438c4 p2
  PATCH_IF (p1 = 0xe8) AND (p2 = 0xffc75935) BEGIN
	WRITE_BYTE 0x5438c3 0x90
	WRITE_LONG 0x5438c4 0x90909090
	PATCH_PRINT ~Patched BGMain.exe at address 0x5438c3.~
  END ELSE BEGIN
	PATCH_PRINT ~No patches made to BGMain.exe.~
	INNER_ACTION BEGIN
	  AT_EXIT ~setup-picking.exe --uninstall~
	END
  END
BUT_ONLY_IF_IT_CHANGES
This works on a patched ToB executable (including the one used in Tutu and theoretically BGT) - a failed pickpocketing attempt does not turn the target hostile. Thank Taimon for the hex references.

Now, of course, we would just need to detect when this happens and invoke some dialogue or scripting... :unsure:

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#23 Taimon

Taimon
  • Member
  • 387 posts

Posted 18 May 2009 - 03:55 AM

Maybe it's possible to set the status flag that triggers StealFailed().
Otherwise it would be difficult to detect the failed attempt.

#24 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 18 May 2009 - 04:54 AM

A failed pickpocket attempt is treated as an attack by the engine.

Not anymore. "The hardcodedness is no bar to our hackery.


Cool! :) Is there a chance to make it so that a successful pickpocket attempt doesn't break stealth/invisibility?

Now, of course, we would just need to detect when this happens and invoke some dialogue or scripting... :unsure:


There's already a PickPocketFailed() trigger but I don't think it works in BG2:ToB. Perhaps Taimon could check it out as well.

#25 Taimon

Taimon
  • Member
  • 387 posts

Posted 18 May 2009 - 05:38 AM

No promises (and no ETA), but I'll take a look.

#26 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 18 May 2009 - 06:55 AM

There's already a PickPocketFailed() trigger but I don't think it works in BG2:ToB.

Correct - I tested it several ways with no luck, so the IESDP is right as usual. However, I know Ascension64 has had luck in the past with reenabling broken triggers, so it's doable in theory. That would be the best solution anyway. Otherwise, what Taimon suggested could work as a backup - redirecting it to the StealFailed(), which would mean the same dialogue would kick in for any failed steal attempts (store thieving and pickpocketing).

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#27 Taimon

Taimon
  • Member
  • 387 posts

Posted 20 May 2009 - 11:00 AM

Learnt quite a bit about the engine today.
It turns out that "enabling" the PicketpocketFailed() trigger also solves the auto hostile problem, so you don't need the previous exe patch.
[In fact I'm just replacing AttackedBy() with PickpocketFailed() but this isn't so obvious when you look at cryptic assembly listings. ;)]
COPY "bgmain.exe" "bgmain.exe"
	PATCH_IF ((LONG_AT 0x5437B2) == 0xAA5E6C) THEN BEGIN
		WRITE_LONG 0x5437B2 0xAA5F22
	END ELSE PATCH_PRINT "0xBAADF00D"
BUT_ONLY

However, the invisibility problem is difficult to patch.
First off, I think you are leaving shadows as soon as you click on the steal icon.
And then there is an 0x88 effect (force visible) in the pickpocket code, that gets dispatched before the sucess of the pickpocket attempt is determined. (You could get away with a protection from opcode, but I don't think that's the right way.)

#28 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 20 May 2009 - 11:22 AM

[In fact I'm just replacing AttackedBy() with PickpocketFailed() but this isn't so obvious when you look at cryptic assembly listings. ;)]

Very, very nice. I just tested this in conjunction with a PickPocketFailed() trigger in the target's script and it worked brilliantly :cheers:. So I guess it's a matter of extending the scripts of all non-enemies who can be pickpocketed (maybe a la p5tweaks) unless there's an easier method (preferably without mucking up baldur.bcs further).

The invisibility thing is an annoyance, but maybe you'll think of something. If you can suppress it somehow, it can also be enabled with the same PickPocketFailed() script perhaps, since IMO it should be broken for failed attempts but not for successful ones.

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#29 Jarno Mikkola

Jarno Mikkola

    The Imp in his pink raincoat.

  • Member
  • 10911 posts

Posted 20 May 2009 - 12:12 PM

However, the invisibility problem is difficult to patch.
First off, I think you are leaving shadows as soon as you click on the steal icon.

It actually should happen at the end of the turn, not immediately... just like in the attack phase of the backstabbing... of course I might be badly off though.
No I am not off, as the icon that's used, is used in disarming traps too and I have done that many times under the eyes of opponents and succeeded to get away.

Edited by Jarno Mikkola, 20 May 2009 - 12:14 PM.

Deactivated account. The user today is known as The Imp.


#30 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 20 May 2009 - 12:21 PM

No I am not off, as the icon that's used, is used in disarming traps too and I have done that many times under the eyes of opponents and succeeded to get away.

I think the thieving icon (mask) is used for picking pockets and opening locks, whereas the trap finding/disarming skill has a separate icon (looks like a trap).

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#31 Taimon

Taimon
  • Member
  • 387 posts

Posted 21 May 2009 - 01:07 AM

However, the invisibility problem is difficult to patch.
First off, I think you are leaving shadows as soon as you click on the steal icon.

It actually should happen at the end of the turn, not immediately...

What I meant was, that clicking the icon triggers the leaving shadows action. When it actually happens is different matter. (But I think you are right.)

I need more info on how exactly this should be handled. (Pickpocketing when in hide mode and when under invisibility.)

#32 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 21 May 2009 - 07:19 AM

Learnt quite a bit about the engine today.
It turns out that "enabling" the PicketpocketFailed() trigger also solves the auto hostile problem, so you don't need the previous exe patch.
[In fact I'm just replacing AttackedBy() with PickpocketFailed() but this isn't so obvious when you look at cryptic assembly listings. ;)]

COPY "bgmain.exe" "bgmain.exe"
	PATCH_IF ((LONG_AT 0x5437B2) == 0xAA5E6C) THEN BEGIN
		WRITE_LONG 0x5437B2 0xAA5F22
	END ELSE PATCH_PRINT "0xBAADF00D"
BUT_ONLY


Great work! :new_thumbs: Do you mind if I borrow this for my own mods? (with due credit to you and Miloch of course)

I need more info on how exactly this should be handled. (Pickpocketing when in hide mode and when under invisibility.)


In my view, a successful pickpocket attempt shouldn't apply the "force visible" opcode to the thief, but a failed one should. OTOH, I don't particularly mind that pickpocketing exits the stealth modal state as long as the thief isn't instantly rendered visible and still has that 6 second window of opportunity to re-enter stealth mode.

#33 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 21 May 2009 - 07:25 AM

So I guess it's a matter of extending the scripts of all non-enemies who can be pickpocketed (maybe a la p5tweaks)


Yup, I was thinking of doing something like that and re-using my approach for failed store theft attempts with some minor dialogue adjustments.

#34 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 21 May 2009 - 09:57 AM

Yup, I was thinking of doing something like that and re-using my approach for failed store theft attempts with some minor dialogue adjustments.

RR is probably the best place for this patch. I'm tempted to pinch it too, but you wouldn't want this patch going in more than once in a multi-mod install.

The main caveat would be that RR (or whatever mod this goes in) would have to be installed fairly late, possibly even last. The reason for that is that it'll have to extend all scripts of potential pickpocketing targets, including mod-added creatures and merchants. Of course, I could include the PickPocketFailed() block in my creature scripts, and the related dialogue, but it'll do nothing without the patch, and I wouldn't want to put in the patch without accounting for all targets.

If you need help with the code, let me know (or Taimon would be even better, if he's got time to look at that too). There's code in p5tweaks you might be able to adapt (in p5_script.tpa) that conditionally extends scripts with ACTION_PHP_EACH. Nythrun, the bigg and Taimon went over it somewhat, but it might need to be reoptimised with the latest know-how.

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#35 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 21 May 2009 - 10:23 AM

If you need help with the code, let me know (or Taimon would be even better, if he's got time to look at that too). There's code in p5tweaks you might be able to adapt (in p5_script.tpa) that conditionally extends scripts with ACTION_PHP_EACH. Nythrun, the bigg and Taimon went over it somewhat, but it might need to be reoptimised with the latest know-how.


I was thinking of something along these lines:

// Taimon and Miloch's EXE patch for re-enabling the PickPocketFailed() trigger

COPY "bgmain.exe" "bgmain.exe"
	PATCH_IF ((LONG_AT 0x5437B2) == 0xAA5E6C) THEN BEGIN
		WRITE_LONG 0x5437B2 0xAA5F22
	END ELSE PATCH_PRINT "0xBAADF00D"
BUT_ONLY_IF_IT_CHANGES


COMPILE ~RR/RR_CORE/COMPILE/RR#PICKP.BAF~										  // compile the new anti-pickpocketing script
COMPILE ~RR/RR_CORE/COMPILE/RR#PICKP.D~											// RR's new pickpocket related dialogue


// Extend creature scripts

COPY_EXISTING_REGEXP GLOB ~^.+\.cre$~ ~override~								   // parse through all creatures in the game
PATCH_IF (%SOURCE_SIZE% > 0x2d3) THEN BEGIN										// file size sanity check (filters out 0 byte files i.e. ALLOW_MISSING)
READ_ASCII 0x248 "ovrscript"
READ_BYTE  0x270 "allegiance"
READ_BYTE  0x271 "general"
 PATCH_IF (%allegiance% = "128" AND %general% = "1") BEGIN						 // only patch non-hostile humanoid creatures
  PATCH_IF NOT FILE_EXISTS_IN_GAME ~%ovrscript%.bcs~ THEN BEGIN					// if the override script doesn't exist
	WRITE_ASCII 0x248 ~RR#PICKP~ #8												// assign RR#PICKP.BCS as the new override script
  END ELSE
	   INNER_ACTION BEGIN
		ACTION_IF FILE_EXISTS_IN_GAME ~%ovrscript%.bcs~ AND NOT FILE_CONTAINS_EVALUATED (~%ovrscript%.bcs~ ~RR#PICKP~) BEGIN
		EXTEND_TOP ~%ovrscript%.bcs~ ~RR/RR_CORE/COMPILE/RR#PICKP.BAF~			 // otherwise just extend the script unless it was already done
		END	
	   END																		 // ends inner action
 END
END																				// end file size sanity check
BUT_ONLY_IF_IT_CHANGES

With RR#PICKP.BAF being:

IF
	PickPocketFailed([PC])		
	Allegiance(Myself,NEUTRAL)
	See([PC])
	!StateCheck(Myself,CD_STATE_NOTVALID)
THEN
	RESPONSE #100
		StartDialogOverride("RR#PICKP",LastTrigger)
END

You are right about this needing to go after most other mods though.

Edited by aVENGER, 21 May 2009 - 10:27 AM.


#36 Taimon

Taimon
  • Member
  • 387 posts

Posted 21 May 2009 - 11:00 AM

Great work! :new_thumbs: Do you mind if I borrow this for my own mods? (with due credit to you and Miloch of course)

Feel free to use any code that I publish (without asking). As far as I'm concerned you don't even need to credit me.
(WTFPL or something like that. :))

I'd suggest you replace the PATCH_PRINT with a meaningful error message, though. (The "0xBAADF00D" is a bad joke for reverse engineers. [IsMemoryBadFood()])

In my view, a successful pickpocket attempt shouldn't apply the "force visible" opcode to the thief, but a failed one should.

This will be difficult to accomplish because like I said, the effect is added before the real pickpocket attempt.
Let's see if we can somehow delete the effect afterwards.

Edited by Taimon, 21 May 2009 - 11:05 AM.


#37 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 21 May 2009 - 12:10 PM

I was thinking of something along these lines:

That should work, in theory. It may or may not be more efficient than ACTION_PHP_EACH. Taimon could probably say. I'm not sure why Nythrun decided to use that, unless just to show off her mad coding skills. Here's an adapted version of that:
COMPILE ~rr/rr_core/compile/rr#pickp.baf~

COPY_EXISTING_REGEXP GLOB ~^.*\.cre$~ ~override~
  PATCH_IF SOURCE_SIZE > 0x2d3 BEGIN
	READ_BYTE 0x270 g1 //Allegiance
	READ_BYTE 0x271 g2 //General
	PATCH_IF (g1 = 128) AND (g2 = 1) BEGIN //Neutral humanoids only
	  PATCH_IF (~%SOURCE_RES%~ STRING_EQUAL_CASE ~charbase~ = 0) BEGIN //Exclude charbase.cre
		READ_ASCII 0x248 ~vs~ //Override script
		PATCH_IF FILE_EXISTS_IN_GAME ~%vs%.bcs~ BEGIN //If override script exists
		  PATCH_IF NOT VARIABLE_IS_SET $df(EVALUATE_BUFFER ~%vs%~) BEGIN //And not already marked
			SPRINT $df(EVALUATE_BUFFER ~%vs%~) ~%vs%~ //Add to extend buffer
		  END
		END ELSE BEGIN
		  WRITE_EVALUATED_ASCII 0x248 ~rr#pickp~ #8 //Otherwise add new script
		END
	  END
	END
  END
BUT_ONLY_IF_IT_CHANGES

ACTION_PHP_EACH df AS i => xs BEGIN
  EXTEND_TOP ~%xs%.bcs~ ~override/rr#pickp.bcs~
END
Maybe Taimon has some clever trick that's even more efficient. But whichever method you use, you probably want to exclude charbase.cre as above.

Edit: typo

Edited by Miloch, 21 May 2009 - 12:36 PM.

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#38 Taimon

Taimon
  • Member
  • 387 posts

Posted 22 May 2009 - 05:20 PM

In my view, a successful pickpocket attempt shouldn't apply the "force visible" opcode to the thief, but a failed one should.

This will be difficult to accomplish because like I said, the effect is added before the real pickpocket attempt.
Let's see if we can somehow delete the effect afterwards.

No, not possible.
But I did some magic to first disable it and then hide those 26 bytes somewhere in the pickpocket failed block (without changing the size). :)
// part1
OUTER_SET off_part1 = 0x00543667
OUTER_SET len_part1 = 0x1a
OUTER_PATCH_SAVE orig_part1 "" BEGIN
	INSERT_BYTES 0x00 len_part1
	WRITE_LONG   0x00 0x958b006a
	WRITE_LONG   0x04 0xffffff10
	WRITE_LONG   0x08 0xcc0d8b52
	WRITE_LONG   0x0c 0x8100b773
	WRITE_LONG   0x10 0x006c48c1
	WRITE_LONG   0x14 0x5b7ce800
	WRITE_SHORT  0x18 0xffc7
END

OUTER_PATCH_SAVE patch_part1 "" BEGIN
	INSERT_BYTES 0x00 len_part1
	WRITE_LONG   0x00 0x90909090
	WRITE_LONG   0x04 0x90909090
	WRITE_LONG   0x08 0x90909090
	WRITE_LONG   0x0c 0x90909090
	WRITE_LONG   0x10 0x90909090
	WRITE_LONG   0x14 0x90909090
	WRITE_SHORT  0x18 0x9090
END

// part2
OUTER_SET off_part2 = 0x005438a2
OUTER_SET len_part2 = 0x44
OUTER_PATCH_SAVE orig_part2 "" BEGIN
	INSERT_BYTES 0x00 len_part2
	WRITE_LONG   0x00 0xfe6c958b
	WRITE_LONG   0x04 0x9589ffff
	WRITE_LONG   0x08 0xfffffeac
	WRITE_LONG   0x0c 0x858b006a
	WRITE_LONG   0x10 0xfffffeac
	WRITE_LONG   0x14 0xcc0d8b50
	WRITE_LONG   0x18 0x8100b773
	WRITE_LONG   0x1c 0x006c48c1
	WRITE_LONG   0x20 0x5935e800
	WRITE_LONG   0x24 0x8d8bffc7
	WRITE_LONG   0x28 0xfffffd44
	WRITE_LONG   0x2c 0x8d8b118b
	WRITE_LONG   0x30 0xfffffd44
	WRITE_LONG   0x34 0x891052ff
	WRITE_LONG   0x38 0xfffd9c85
	WRITE_LONG   0x3c 0x9c858bff
	WRITE_LONG   0x40 0x8afffffd
END

OUTER_PATCH_SAVE patch_part2 "" BEGIN
	INSERT_BYTES 0x00 len_part2
	WRITE_LONG   0x00 0x8b51006a
	WRITE_LONG   0x04 0xb773cc0d
	WRITE_LONG   0x08 0x48c18100
	WRITE_LONG   0x0c 0xe800006c
	WRITE_LONG   0x10 0xffc75947
	WRITE_LONG   0x14 0x958b006a
	WRITE_LONG   0x18 0xffffff10
	WRITE_LONG   0x1c 0xcc0d8b52
	WRITE_LONG   0x20 0x8100b773
	WRITE_LONG   0x24 0x006c48c1
	WRITE_LONG   0x28 0x592de800
	WRITE_LONG   0x2c 0x8d8bffc7
	WRITE_LONG   0x30 0xfffffd44
	WRITE_LONG   0x34 0x52ff118b
	WRITE_LONG   0x38 0x90909010
	WRITE_LONG   0x3c 0x90909090
	WRITE_LONG   0x40 0x8a909090
END

COPY "bgmain.exe" "bgmain.exe"
	READ_ASCII off_part1 current_part1 ELSE 0 (len_part1)
	READ_ASCII off_part2 current_part2 ELSE 0 (len_part2)
	PATCH_IF ("%current_part1%" STRING_EQUAL "%orig_part1%")
		 AND ("%current_part2%" STRING_EQUAL "%orig_part2%")
	THEN BEGIN
		WRITE_ASCIIE off_part1 "%patch_part1%" (len_part1)
		WRITE_ASCIIE off_part2 "%patch_part2%" (len_part2)
	END ELSE PATCH_PRINT "Target bytes don't match. Aborting ..."
BUT_ONLY


#39 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 23 May 2009 - 12:35 AM

But I did some magic to first disable it and then hide those 26 bytes somewhere in the pickpocket failed block (without changing the size).

This seemed to work properly on my install. I installed it in conjunction with the other patch (not included in that, right?) and the script extending and went to pinch Phlydia while stealthed and also while invisible. Success did not break either but failure did and I got the dialogue prompt then.

Pretty impressive stuff. Gone are the days when "hardc0ded" = "can't be done" :woot:.

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle


#40 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 23 May 2009 - 01:49 AM

This seemed to work properly on my install. I installed it in conjunction with the other patch (not included in that, right?) and the script extending and went to pinch Phlydia while stealthed and also while invisible. Success did not break either but failure did and I got the dialogue prompt then.


It also worked as intended for me.

Awesome stuff Taimon! :cheers: