Urban Runner : Unlock the problem in the hotel

General chat related to ScummVM, adventure gaming, and so on.

Moderator: ScummVM Team

Post Reply
Sylvain
ScummVM Team Member
Posts: 8
Joined: Wed Jul 14, 2010 10:19 pm

Urban Runner : Unlock the problem in the hotel

Post by Sylvain »

Hello guys,

Well, as you know, in the current state Urban Runner can't currently be completed. For experiment purpose, I'm trying to solve the problem.

The main problem is that we're supposed to interact with some hotspot while the ALLUFEU.VMD video is running (click on the register), it's the first video where it's really important. Another one is when you must put the glasses in the bin, or go fast under the car.

I analysed the script to know what is expected : var32_212 is supposed to be updated with the current frame of the video, and it's supposed to be set to -1 when the video is done. When I set manually var32_212 to some values (for example 100), the hotspots are visible and I can click on the register, so it's a good lead.

I tried to implement a "livePrimary" system in the videoplayer that would start the video, then go back to the script, and the script would periodically update the video, write the good frame number in the variable.

Periodically is the problem : I can't find a good way to plugin the video update in the script execution, I tried to put it in the hotspot evaluate section, but it's sometimes not called enough. I'm thinking that putting it in the retrace is not a good idea.

Has someone any idea about this?

Thanks!

P.S actually the small video in the corner that is sometimes appearing must be a "live video" too.

Sylvain

User avatar
DrMcCoy
ScummVM Developer
Posts: 596
Joined: Sat Dec 17, 2005 1:33 pm
Location: Braunschweig, Germany
Contact:

Re: Urban Runner : Unlock the problem in the hotel

Post by DrMcCoy »

Sylvain wrote:Well, as you know, in the current state Urban Runner can't currently be completed. For experiment purpose, I'm trying to solve the problem.
Help is always welcome. :)
Sylvain wrote:I analysed the script to know what is expected : var32_212 is supposed to be updated with the current frame of the video, and it's supposed to be set to -1 when the video is done. When I set manually var32_212 to some values (for example 100), the hotspots are visible and I can click on the register, so it's a good lead.
Are you sure?
As far as I remember, the scripts only call the video playback once, with the flags to run from start to finish (not frame-by-frame), and the video consists of the whole action.

And afterwards, it's doing a switch within the script-stack, using an empty index, thus screwing up the script stack (which is the current lock-up).

I've been scratching my head about that for quite a while...
Would be great if it would be that easy to solve (and embarassing for me ;)).
Sylvain wrote:I tried to implement a "livePrimary" system in the videoplayer that would start the video, then go back to the script
I don't quite think that's how it's supposed to go.
The opcode is the same as normal video playback, without any different flags.
And as far as I remember, Urban Runner doesn't completely change the video playback functions to only play 1 frame when the lastFrame argument is -1. All other engine versions took that as playing the video till the end, blockingly.

Can you test whether your proposed idea works for all other videos in Urban Runner?
Sylvain wrote:Periodically is the problem : I can't find a good way to plugin the video update in the script execution, I tried to put it in the hotspot evaluate section, but it's sometimes not called enough. I'm thinking that putting it in the retrace is not a good idea.
Hacking these things in is probably not a good idea, the consequences are far too unforseeable.
I'd advise staying close to the disasm there.

Have you noticed any special flags or "magic values" for o6_playVmdOrMusic that indicate that certain videos are "live" videos?

Another thing: You should probably not trust that the current VideoPlayer interface stays the same. I'm currently in the process of completely rewriting CoktelVideo to use the new VideoDecoder interface, changing Gob::VideoPlayer alongside (and enabling 16bit support for Urban Runner).
Well, okay, I've started that some weeks ago, but I'm kinda in a strange state personally, so it's not yet finished. But I'm getting there eventually. ;)

Sylvain
ScummVM Team Member
Posts: 8
Joined: Wed Jul 14, 2010 10:19 pm

Post by Sylvain »

I'm not really sure of anything, I just started studying scummvm/gob 2 days ago, I probably lack some knowledge about the internals.
I'm 100% sure that you're supposed to click on the register during the video, and it's the same video (no cut). During one view of the video you have two clickable hotspots (the bin and the register)

I'm going to explain how I came to this conclusion after 10 hours of script analysis:

(all code here is from EMAM2005.TOT decompilation)

When you click on the bin with the matches, it calls this :

Code: Select all

00004537:sub_4537 {
00004542:	switch (var32_7600) {
00004546:	case -1:
00004555:		o4_playVmdOrMusic("hmx4-18", -1, -1, 0, -1, 4, 256, -1, -1);
00004597:		break;
00004598:	case 4:
00004612:		var8_17699 = 0;
00004619:		var8_17739 = 0;
00004626:		var8_17699 = 1;
00004633:		var32_7952 = 21;
00004636:		sub_15073();
00004650:		var8_11540 = "ALLUFEU";
00004657&#58;		var32_7716 = 5; << this is important this seems to be the video playing mode
00004664&#58;		var32_7600 = -1;
00004667&#58;		sub_12235&#40;&#41;;
00004670&#58;		sub_10622&#40;&#41;;
00004677&#58;		var32_7872 = 103;
00004680&#58;		sub_7549&#40;&#41;;
00004687&#58;		var32_9612 = -1;
00004687&#58;		break;
00004688&#58;	default&#58;
00004696&#58;		sub_12642&#40;&#41;;
00004696&#58;		break;
00004696&#58;	&#125;
00004696&#58;&#125;
This seems to be the "video playing" routine in the script :

Code: Select all

00010622&#58;sub_10622 &#123;
..
case 0 &#58; 
// normal
 "blocking" video

case 2&#58;
// small video in the left corner  
case 3&#58;
// small video in the right corner
case 5&#58;
// live video with action required
The case 5 is interesting here :

Code: Select all

var32_7860 = 0;  << seems to be frame counter &#40;assigned from 212 later on&#41;
var32_212 = 0;  << seems to be frame counter of video &#40;set by the engine directly&#41;, it was -1, it is now set to 0
o4_playVmdOrMusic&#40;&#40;&var8_11540&#41;, 8, 96, -2, 0, 4, 3+128, 0, 255&#41;;  << different flag  0x83 instead of 0x1003 for case 0
OK so the video is launched, at the moment it plays till the end.

Let's just make the "o6_playVmdOrMusic" not blocking. It just plays the first frame, then we go to sub_7549();

Code: Select all

00007549&#58;sub_7549 &#123;
...
00007762&#58;	case 103&#58; << we're in this case
00007776&#58;		var32_7736 = 1;  << setup a special mode for hotspots that we will see later 
00007784&#58;		var16_546 = 1001; << prepares the two hotspots in "undefined mode"
00007792&#58;		var16_548 = 1001;
00007792&#58;		break;
Ok then the script continues normally until we go back in the usual "main" loop :

Code: Select all

00013207&#58;		repeat &#123;
00013214&#58;			sub_14050&#40;&#41;;
00013217&#58;			o1_collisionsBlock&#40;12659&#41;;
00013220&#58;			sub_12320&#40;&#41;;
00013221&#58;		&#125; until &#40;var8_239==1&#41;;
And here in 14050 there is a specific handling case for our "live mode"

Code: Select all

00014050&#58;sub_14050 &#123;
00014055&#58;	if &#40;var32_7736==1&#41; &#123; ...    
then between 00014243 and 00014824, the script compares the current frame time ( var32_7860 ) and 4 times for each hotspot.

There seems to be 5 states for the "dynamic hotspots"
var16_512[var32_7708} of 100] = 1001; (before time 1) then
var16_512[var32_7708} of 100] = 1; (before time 2) then
var16_512[var32_7708} of 100] = 2; (before time 3) then
var16_512[var32_7708} of 100] = 3; (before time 4) then
var16_512[var32_7708} of 100] = 1000; (after time 4), disabled.
These hotspots time numbers are defined by all the assignments in sub_8910.


Why var32_7860 is the frame number? And why 212 too ?

In sub_12694 (which get called quite a lot) , when we are in our "special mode" (var32_7736 == 1) :
var32_7860 = var32_212;

So the dynamic hotspots depends on var32_212...
It can only be the current frame I think.


Why should the var32_21 be set to -1 at the end of the video ?

First clue : var32_7900 is the "special case of video in corner"

Code: Select all

00015016&#58;sub_15016 &#123;
00015021&#58;	if &#40;var32_7900==1&#41; &#123;
00015033&#58;		if &#40;var32_212==-1&#41; &#123;  << if the video finishes, sub_13881 does a pop capture to restore
00015047&#58;			sub_13881&#40;&#41;; 
00015048&#58;			o1_keyFunc&#40;1&#41;;
00015051&#58;			o1_setMousePos&#40;var32_8-1, var32_12&#41;;
00015063&#58;		&#125;
00015064&#58;	&#125;
00015064&#58;&#125;
Second clue : in sub_8014

Code: Select all

00008160&#58;	switch &#40;var32_7872&#41; &#123;
00008164&#58;	case 103&#58;  << in your current state &#40;after allufeu&#41;
00008172&#58;		if &#40;var32_212==-1&#41; &#123;  << whenever video is finished 
00008185&#58;			o4_playVmdOrMusic&#40;"", -1, -1, -1, 0, 0, 0, 0, 0&#41;;
00008219&#58;			var32_7872 = 101;
00008222&#58;			sub_7549&#40;&#41;; << go to another state
00008229&#58;			var8_17698 = 1;
00008236&#58;			var8_17739 = 1;
00008243&#58;			var8_17737 = 2;
00008250&#58;			var32_6520 = 1;
00008251&#58;		&#125;
00008251&#58;		break;
00008252&#58;	&#125;
00008252&#58;&#125;
In the current code, var32_212 is never set so it stays 0 : the "phone menu" is disabled by the script, the hotspots are never shown (after the video) and the video is never finished for the script because it var_212 is never -1 so it can't go back to another state => looks like it's locked up (that's how i understand it anyway) .
Have you noticed any special flags or "magic values" for o6_playVmdOrMusic that indicate that certain videos are "live" videos?
Any video that is played without the 0x1000 flag present seems to be a "live video", this includes all the corner videos (in the orginial game the cursor and hotspots still works when the video in corner appears)
All "normal videos" are played via case 0 of 00010622:sub_10622 , which put the flag 4099
( o4_playVmdOrMusic((&var8_11540), 8, 96, 0, -1, 4, 4099, 0, 255); )
And I disable the "live video" if there is no video in it too (0x100 flag)
So i think the flag 0x1000 means : blocking video.

The annoying thing is that the script calls "Play" once yes :(

With my current tests I can pass the "click on register thing during burning bin" and it goes back to a "ok state" after that (even if I don't click on it actually) and I can progress afterwards. The only problem is that I had to put the video update in hotspots update.
Works fine also for some transition videos and corner videos, except some speed fps issues and audio desynchronisation. I didn't try the entire game yet though but the next "live" video which is when you have to look at someone else typing code on a door works too. There are some surface/backbuffer redraw issues too but I'm really not sure how it works.


Let me know what you think about this. It's a "hacky way" but kinda works. I'm sure there is a better way but the "async" video seems to be certain. It would probably be a good idea to look at dissassembly to know where the var_212 is written to (what debugger/disassembler are you using btw?)




Some other bugs I noticed :

Also because of some changes in 1.1.1, the drawing of some 3D animations is screwed (the fuse thing for example), I think it worked before, I "fixed" that too (in graphics.vmd.renderframe). But you're refactoring this, so I suppose it will be fixed afterwards :)

Code: Select all

	int16 oldWidth = width;
	width = postScaleX&#40;width&#41;;

	int16 drawWidth  = MAX<int16>&#40;0, MIN<int16>&#40;width , sW&#41;&#41;;
	int16 drawHeight = MAX<int16>&#40;0, MIN<int16>&#40;height, sH  &#41;&#41;;

	// Evaluate the block type
	if      &#40;type == 0x01&#41;
		renderBlockSparse  &#40;dest, srcPtr, drawWidth, drawHeight, sW, width&#41;;
	else if &#40;type == 0x02&#41;
		renderBlockWhole   &#40;dest, srcPtr, drawWidth, drawHeight, sW, width&#41;;
	else if &#40;type == 0x03&#41;
		renderBlockRLE     &#40;dest, srcPtr, drawWidth, drawHeight, sW, width&#41;;
	else if &#40;type == 0x42&#41;
		renderBlockWhole4X &#40;dest, srcPtr, drawWidth, drawHeight, sW, width&#41;;
	else if &#40;&#40;type & 0x0F&#41; == 0x02&#41;
		renderBlockWhole2Y &#40;dest, srcPtr, drawWidth, drawHeight, sW, width&#41;;
	else
		renderBlockSparse2Y&#40;dest, srcPtr, drawWidth, drawHeight, sW, width&#41;;

	dest = _vidMemBuffer + postScaleX&#40;_width&#41; * &#40;top - _y&#41; + postScaleX&#40;left - _x&#41;;
	blit&#40;imdVidMem, dest, oldWidth, height&#41;;
Also the text in the first part of the game didn't seem to be loaded, so I moved :

Code: Select all

	if &#40;!loadTOTTextTable&#40;_fileBase&#41;&#41; &#123;
		unload&#40;&#41;;
		return false;
	&#125;
outside of the

Code: Select all

	if &#40;hasTOTRes&#41; &#123;   
check

And it worked :)

(sorry for the long text)

User avatar
DrMcCoy
ScummVM Developer
Posts: 596
Joined: Sat Dec 17, 2005 1:33 pm
Location: Braunschweig, Germany
Contact:

Post by DrMcCoy »

Hmm, yes, it seems like you're onto something there. Thanks. :)
When I looked at the problem, I've been working my way around it starting from the lock-up and going backwards. Apparently I've messed up somewhere. :P
Sylvain wrote:So the dynamic hotspots depends on var32_212...
It can only be the current frame I think.
Curious about var32_212. The older engine generations only wrote the current frame into var32_44. Need to check that in the disasm.
Sylvain wrote:Any video that is played without the 0x1000 flag present seems to be a "live video"
Hmmkay...
Sylvain wrote:Let me know what you think about this. It's a "hacky way" but kinda works. I'm sure there is a better way but the "async" video seems to be certain. It would probably be a good idea to look at dissassembly to know where the var_212 is written to
Yeah, seems I need to trace a lot of the Urban Runner video code. Oh, joy.
Starting from Woodruff, the video code in gob games is a real mess. Huge amount of code, including function pointers for cache manipulation from different sources (CD, HD, within STK, ...). The flags and magic values get evaluated where they're needed, i.e. some at the start, some 20 levels deep in the call stack, some copied to special structs and then evaluated way later, .... Hell on earth. :P
The current Gob::VideoPlayer interface partly resembles that mess :P.
Sylvain wrote:what debugger/disassembler are you using btw
I'm using IDA.
Sylvain wrote:Also the text in the first part of the game didn't seem to be loaded, so I moved
Hmm, yes, I think I was overprotective there. Though I need to check that it doesn't do any funny stuff when there's a TOT-internal text table.

User avatar
Red_Breast
Posts: 785
Joined: Tue Sep 30, 2008 10:33 pm
Location: The Bar Of Gold, Upper Swandam Lane.

Post by Red_Breast »

I played the game with ScummVM about a year ago to see how far I could get. I reached a point where it seems you need to light a match and throw it into a trash bin to cause a diversion. Is that the same part as this 'click on register' part? I ask as I can't recall why you need to cause a diversion but maybe it's because you need to take a look at a register. This part takes place inside where there are a number of chairs and tables and I think you ask a lady, sitting at one of the tables, for some help.
Annoyingly I don't have the save games anymore.

Sylvain
ScummVM Team Member
Posts: 8
Joined: Wed Jul 14, 2010 10:19 pm

Post by Sylvain »

Yes it's the part we're talking about. You're blocked at this place because you can't click on the register.

I loaded the game in IDA (too bad we can't debug it because it's 16 bits !). I get the places where IcOpen / IcDecompress functions are called but it's very hard to go from there :D
Were you able to launch the game through a debugger ? Or do you look only at the disassembly ?

User avatar
Red_Breast
Posts: 785
Joined: Tue Sep 30, 2008 10:33 pm
Location: The Bar Of Gold, Upper Swandam Lane.

Post by Red_Breast »

Sylvain wrote:
Were you able to launch the game through a debugger ? Or do you look only at the disassembly ?
Sorry Sylvain I should of made it clear I'm not attempting to solve this as I wouldn't know how. I can understand how you might of thought I was trying to help as the only other posters in the thread, yourself and the Dr, both know what you're talking about when it comes to code whilst my only claim to fame regarding Urban runner was falling for the last ScummVM April Fools joke.

User avatar
clone2727
Retired
Posts: 1592
Joined: Fri Jun 09, 2006 8:23 pm
Location: NJ, USA

Post by clone2727 »

Red_Breast wrote:
Sylvain wrote:
Were you able to launch the game through a debugger ? Or do you look only at the disassembly ?
Sorry Sylvain I should of made it clear I'm not attempting to solve this as I wouldn't know how.
I'm pretty sure Sylvain directed that at DrMcCoy.

Post Reply