#10751 closed defect (fixed)

QFG4: Rope obscured by bkg when rescuing Igor

Reported by: Vhati Owned by: bluegr
Priority: low Component: Engine: SCI
Keywords: SCI32 original has-pull-request Cc:
Game: Quest for Glory 4

Description

ScummVM 2.1.0git3770-g15306581ab (Oct 18 2018 04:27:32)
Windows 7 64bit
QFG4 CD (English)

When Igor is trapped in the graveyard...

After climbing a tree and using the grapnel, the rope is briefly obscured by the facade of a background tomb, during a sequence where the hero climbs down and pulls.

File - 5kb MD5 - Full MD5
RESOURCE.000 - 263dce4aa34c49d3ad29bec889007b1c - 1364ba69e3c0abb68cc0170650a56692
RESOURCE.AUD - c39521bffb1d8b19a57394866184a0ca - 71098b9e97e20c8941c0e4812d5f906f
RESOURCE.MAP - aba367f2102e81782d961b14fbe3d630 - 801a04cc6aa5d437681a2dd0b6545248
RESOURCE.SFX - 3cf95e09dab8b11d675e0537e18b499a - 7c858d7253f86dab4cc6066013c5ecec

Attachments (3)

sci.021 (70.3 KB ) - added by Vhati 12 months ago.
SavedGame - Grapnel
Grapnel.png (131.2 KB ) - added by Vhati 12 months ago.
Screenshot - Grapnel
Pic Priority (CD) - Room 500.png (4.2 KB ) - added by Vhati 11 months ago.
Pic Priority (CD) - Room 500

Download all attachments as: .zip

Change History (16)

by Vhati, 12 months ago

Attachment: sci.021 added

SavedGame - Grapnel

by Vhati, 12 months ago

Attachment: Grapnel.png added

Screenshot - Grapnel

comment:1 by digitall, 12 months ago

@Vhati: Thanks for the bug report. Could you try testing this with the original SCI interpreter to see if this occurs in the original as well?

comment:2 by Vhati, 12 months ago

The original interpreter also does this.

comment:3 by digitall, 12 months ago

Keywords: original added

comment:4 by Vhati, 12 months ago

The floppy edition under ScummVM did not have this bug.


ScummVM 2.1.0git3797-ge7d23d2cd9 (Oct 25 2018 04:17:12)
Windows 7 64bit
QFG4 Floppy 1.1a + note patch (English)

File - 5kb MD5 - Full MD5
RESOURCE.000 - f64fd6aa3977939a86ff30783dd677e1 - ff42260a665995a85aeb277ad80aac8a
RESOURCE.MAP - d10a4cc177d2091d744e2ad8c049b0ae - 3695b1b0a1d15f3d324ea9f0cc325245
RESOURCE.SFX - 3cf95e09dab8b11d675e0537e18b499a - 7c858d7253f86dab4cc6066013c5ecec

by Vhati, 11 months ago

Pic Priority (CD) - Room 500

comment:5 by Vhati, 11 months ago

Quick and dirty way to skip to Igor's rescue.

  • Create a rogue.
  • Set flag 37 (Heard "Igor is missing!" outside the Burgomeister's office).
    • vv g 502 1024
  • Give yourself the rope.
    • send hero get 16
  • Teleport to the graveyard.
    • room 500
  • Click the rope & grappling hook on the tree branch.
Last edited 11 months ago by Vhati (previous) (diff)

comment:6 by Vhati, 11 months ago

SCI Companion says the background Pic has priority regions for the crypt pillars (priority 106).

With some experimentation I learned adjusting priority doesn't update the graphics. Gotta hide/show as well. Batches of commands can be done together from the debugger before dismissing it.

send rope2 setPri 1000
send rope2 hide
send rope2 show

Giving a rope priority 107 was exactly enough to move in front of the pillars.


Breakpoints confirm bigBranch::doVerb(grapnel) is assigning priority (rope1:148, rope2:116).

Start a fresh rescue... climb the tree, click the grapnel on the branch... Sending hide/show is enough to bring both ropes to the front.

When hero comes down, pulling is animated, and the rope comes to the front on its own.

Last edited 11 months ago by Vhati (previous) (diff)

comment:7 by Vhati, 11 months ago

Diffing script 500, CD vs floppy, reveals some changes.
Nothing rope-related stands out though.

The speed slider doesn't help. CD always has a problem; floppy never does.


rope1 and rope2 are Actors, whose ancestry is Feature/View/Prop.


script 64998 - View::setPri() is the same.

(method (setPri param1)
	(cond 
		((== argc 0) (= fixPriority 1))
		((== param1 -1) (= fixPriority 0))
		(else (= priority param1) (= fixPriority 1))
	)
)

script 64998 - Actor::doit() changed, but they still have this.

(if (and (& -info- $0008) (self isNotHidden:))
	(UpdateScreenItem self)
)

script 64950 - View::isNotHidden()

(method (isNotHidden)
	(return (not (& signal $0008)))
)
Last edited 11 months ago by Vhati (previous) (diff)

comment:8 by Vhati, 11 months ago

bigBranch::doVerb(grapnel) is calling init() and setPri().
That's the moment it becomes visible, albeit obscured.


script 500 - bigBranch::doVerb(grapnel)

(rope1 init: setPri: 148)
(rope2 init: setPri: 116)
(global2 setScript: sClimbDown)

rope2 starts out with signal=24576 aka 0x6000.
If I do "send rope2 signal 24577", move the mouse to the icon bar, and dismiss the debugger... the rope remains obscured... until I move the mouse off the icon bar to unpause the game. Then it is immediately repainted, fully.


The script doesn't naturally signal like that until...

script 500 - sTryTree::changeState()

(7
	(rope2
		signal: (| (rope2 signal?) $0001)
		setCycle: End self
	)
)
# ...
(12
	(global0 view: 7 setLoop: 0 1 setCel: 0 setCycle: Fwd)
	(rope1
		signal: (| (rope1 signal?) $0001)
		setCycle: End
		setStep: 1 1
		setMotion: MoveTo (rope1 x?) (+ (rope1 y?) 16)
	)
	(rope2
		signal: (| (rope2 signal?) $0001)
		setStep: 1 1
		setMotion: MoveTo (+ (rope2 x?) 50) (- (rope1 y?) 50)
	)
	(igor show:)
	(headStone
		signal: (| (headStone signal?) $0001)
		setCycle: Beg self
	)
)

And those are the moments rope2 and rope1 get painted properly.


"send rope2 doit" didn't help.

"logkernel UpdateScreenItem"

# Floppy when the ropes first appear.
kUpdateScreenItem: 0044:3786 (rope1) = 1
kUpdateScreenItem: 0044:381c (rope2) = 1

"bp_method rope2::doit" tripped.
"vo rope2 priority" said 116 already at that moment, and UpdateScreenItem() ran.

# CD, nothing until after hero climbs down and pulls.
kUpdateScreenItem: 0044:3cf1 (rope2) = 1
kUpdateScreenItem: 0044:36d5 (moss) = 1
kUpdateScreenItem: 0044:3cf1 (rope2) = 1
kUpdateScreenItem: 0044:3cf1 (rope2) = 1
Last edited 11 months ago by Vhati (previous) (diff)

comment:9 by Vhati, 11 months ago

Actor::doit() changed, but they still have this.

Ah. It moved though.


Floppy script 64998 - Actor::doit()

(method (doit &tmp temp0 temp1 temp2 temp3 temp4 temp5 temp6 temp7)
	(if script (script doit:))
	(if code (code doit: self))

# This condition fails, but it doesn't matter.
#   UpdateScreenItem() is outside.
	(if (& signal notUpd)
		(if viewer (viewer doit: self))
		(if avoider (avoider doit:))
		(if mover
			(if
			(and (& scaleSignal $0001) (not (& scaleSignal $0004)))
				(= temp5 (>> origStep $0008))
				(= temp6 (& origStep $00ff))
				(= temp3
					(if (= temp7 (/ (* temp5 scaleX) 128)) else 1)
				)
				(= temp4
					(if (= temp7 (/ (* temp6 scaleY) 128)) else 1)
				)
				(if (or (!= temp3 xStep) (!= temp4 yStep))
					(self setStep: temp3 temp4 1)
				)
			)
			(if mover (mover doit:))
		)
		(if scaler (scaler doit:))
		(if cycler
			(= temp1 brLeft)
			(= temp2 brRight)
			(cycler doit:)
			(cond 
				((not (& signal $0020)))
				(baseSetter (baseSetter doit: self))
				(else (BaseSetter self))
			)
		)
	)
	(= xLast x)
	(= yLast y)
	(if (and (& -info- $0008) (self isNotHidden:))
		(UpdateScreenItem self)
	)
)



CD script 64998 - Actor::doit()

(method (doit &tmp [temp0 2] temp2 temp3 temp4)
	(if robot (robot doit:))
	(if script (script doit:))
	(if code (code doit: self))

# This condition fails as doit() is repeatedly called.
	(if (& signal notUpd)
		(if viewer (viewer doit: self))
		(if avoider (avoider doit:))
		(if mover (mover doit:))
		(if cycler (cycler doit:))
		(if (& -info- $0008)
			(if scaler (scaler doit:))
			(= xLast x)
			(= yLast y)
# So this doesn't happen.
			(if (self isNotHidden:) (UpdateScreenItem self))
			(if
				(and
					(& scaleSignal $0001)
					(not (& scaleSignal $0004))
					(!= scaleX oldScaleX)
				)
				(= oldScaleX scaleX)
				(= temp2
					(if
						(= temp4
							(>> (+ (* (>> origStep $0008) scaleX) 64) $0007)
						)
					else
						1
					)
				)
				(= temp3
					(if
						(= temp4
							(>> (+ (* (& origStep $00ff) scaleY) 64) $0007)
						)
					else
						1
					)
				)
				(if (or (!= temp2 xStep) (!= temp3 yStep))
					(self setStep: temp2 temp3 1)
				)
			)
			(cond 
				((not (& signal $0020)))
				(baseSetter (baseSetter doit: self))
				(else (BaseSetter self))
			)
		)
	)
)



Dunno what's up with the label "notUpd".
Disassembly says that's an AND between "signal" and a literal 1.


Which means this notifies the rope to call UpdateScreenItem().

(rope2 signal: (| (rope2 signal?) $0001))

That sets signal's 1 bit to satisfy the condition.

Last edited 11 months ago by Vhati (previous) (diff)

comment:10 by Vhati, 11 months ago

Maybe I could tweak the signal value the ropes are instantiated with?

script 500

(instance rope1 of Actor
	(properties
		x 100
		y -10
		view 502
		signal $6000
	)
)

(instance rope2 of Actor
	(properties
		x 127
		y -5
		view 502
		loop 1
		signal $6000
	)
)

That'd be tidy. Except I don't know how to disassemble/patch those blocks.


Hrm. I think I found them. In heap 500's raw bytes. 127 was a distinctive number.
(In SCI Companion, list the heaps, right-click heap 500 and "view raw data". Hex values coincide with an instance's properties list in SCI Companion's disassembly.)

Guess that means I can't patch there.

Last edited 11 months ago by Vhati (previous) (diff)

comment:11 by Vhati, 11 months ago

Correction, I CAN patch the heap, with no special effort.

Except the "signal" value in particular doesn't survive init().
Gotta set it elsewhere then...


EDIT: No wait, it works! Took a little special effort. My savegame was IN the graveyard. I needed to re-enter the room for my heap patch to work.

Last edited 11 months ago by Vhati (previous) (diff)

comment:12 by Vhati, 11 months ago

Keywords: has-pull-request added

Pull Request: SCI32: Fix QFG4 obscured ropes when rescuing Igor

comment:13 by bluegr, 10 months ago

Owner: set to bluegr
Resolution: fixed
Status: newclosed

Thanks for your work! The pull request has been merged, so this can be closed now

Note: See TracTickets for help on using tickets.