Scripting Secrets

Discussion in 'Scripting' started by darmagon, May 28, 2006.

Remove all ads!
  1. Gaear

    Gaear Bastard Maestro Administrator

    Joined:
    Apr 27, 2004
    Messages:
    10,996
    Likes Received:
    23
    A better way to run off

    In ToEE, the attachee.runoff(attachee.location-x) script is not always the greatest. For one thing, mobs generally won't actually 'run' anywhere, preferring to just fade away, unless they are running toward a location defined by a different mob. :dizzy: (ToEE ...!) They seem to do it right sometimes on small maps, but large maps almost always fail in my experience, and you end up with the underwhelming drama where an NPC announces his rapid departure and then just stands there until he fades away like he was transported in Star Trek.

    Well there is a better way, using standpoints. If you assign a mob new standpoints, and it has both its waypoints by day and waypoints by night NPC flags set (so it can do it at any time of day), it will proceed upon command from it's current position to its new standpoint. So you could have an NPC declare that it is leaving, then end the dialogue and run the new standpoints script, and it will actually run off in search of it's new standpoint. If you increase its walk speed to something faster, it will actually appear to run as well. Then you simply turn the mob off on a timed event script a few seconds later and it will really be gone. Strategically plot the new standpoints so that they are in the direction you want the mob to go, and you're all set.

    Here's an example script:

    Code:
    def uncle_jimmy_exit( attachee, triggerer ):
    	attachee.standpoint_set( STANDPOINT_NIGHT, xxx )
    	attachee.standpoint_set( STANDPOINT_DAY, xxx )
    	attachee.obj_set_int(obj_f_speed_walk, 1075353216)
    	game.timevent_add( uncle_jimmy_off, ( attachee, triggerer ), 4000 )
    	return RUN_DEFAULT
    
    def uncle_jimmy_off( attachee, triggerer ):
    	attachee.object_flag_set(OF_OFF)
    	return RUN_DEFAULT
    This will make Uncle Jimmy run away to his new standpoint and turn off after four seconds. Pretty simple really, but I wasted a lot of time trying to get the regular run_off thing to work right first before I just went to this instead.

    run_off would also sometimes fail to really turn the mob off (most famously with Noblig in Hickory Branch), so setting the OF_OFF flag is better for that too.

    [EDIT]

    Okay, so attachee.runoff inexplicably started working properly when the attachee is assigned an actual coordinate to runoff to as opposed to the 'attachee.location-x' thing, although it didn't work before. Assuming it works, this is the preferred method.

    Add this to the mob's san_heartbeat script:

    Code:
    if (whatever control vars you assign):
    	game.timevent_add( uncle_jimmy_exit, ( attachee, triggerer ), 200 )
    	control var so it only happens once
    This will make the mob execute the following 2/10 of a second after its departure speech (you don't want it waiting around too long because somebody is bound to attack it):

    Code:
    def uncle_jimmy_exit( attachee, triggerer ):
    	attachee.npc_flag_unset(ONF_WAYPOINTS_DAY)
    	attachee.npc_flag_unset(ONF_WAYPOINTS_NIGHT)
    	attachee.standpoint_set( STANDPOINT_NIGHT, 629 )
    	attachee.standpoint_set( STANDPOINT_DAY, 629 )
    	attachee.standpoint_set( STANDPOINT_SCOUT, 629 )
    	attachee.runoff( location_from_axis( xxx, xxx ) )
    	game.timevent_add( uncle_jimmy_off, ( attachee, triggerer ), 8000 )
    	return RUN_DEFAULT
    Lines 1 and 2 stop the mob running any waypoints if they are assigned.

    Lines 3 and 4 are a failsafe in case the mob decides to run the waypoints anyway. The new standpoints should be the same as those defined in attachee.runoff. It will run to those same coordinates.

    Line 5 is an interesting thing that I discovered - you can also set a scoutpoint. It should be the same as the standpoints. The mob won't run to it though as near as I can tell ... just another failsafe. Disable it if you like.

    Line 6 is the runoff bit.

    Line 7 is another failsafe to make sure the mob turns off after x seconds (long enough to get it out of view), pointing to this:

    Code:
    def uncle_jimmy_off( attachee, triggerer ):
    	attachee.object_flag_set(OF_OFF)
    	control var
    	return RUN_DEFAULT
    The important part of the attachee.runoff script is that it includes 'location_from_axis( xxx, xxx )' exactly, without any Ls before the coordinates. These coordinates should be the same as the new standpoints.

    This will make the mob actually run in the direction of the coordinates (not walk fast), and it will fade away as well.

    Lastly, as a final failsafe, add this to the mob's san_hearbeat script:

    Code:
    if (whatever control vars you assign):
    	attachee.object_flag_set(OF_OFF)
    When it works, it seems to ... work. ;)
     
  2. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,618
    Likes Received:
    61
    Dynamically Changing Background Graphics

    First, kudos to Ted for finding out that the game does update graphics in runtime and getting me started on this - well done :)

    So, here's the deal - you can manipulate the game's art files using Python scripting.

    To be precise, the map art will update as soon as you scroll away and return to it. A map change will do too of course.

    Thus, to change between graphics, you'd probably do something like this -
    1. Choose the tiles you wish to dynamically alter (e.g. let's use 00220021.jpg as an example)
    2. Create 'original' variants so you can switch back (e.g. 00220021orig.jpg)
    [​IMG]

    3. Create an 'alt' variant (00220021alt.jpg)

    [​IMG]

    4. Create a script that reads a file's contents and overwrites another. (I had hoped there would be a simple 'rename' command, alas it seems no such command exists in ToEE's python, unless someone manages to import the 'os' library)

    Example code:
    Code:
    def alter_tile():
    	f = open('//art/ground/DEEP_SWAMP_02_Cellar/00220021alt.jpg', 'rb')
    	temp = f.read()
    	temptell = f.tell()
    	
    	ff = open('//art/ground/DEEP_SWAMP_02_Cellar/00220021.jpg', 'wb')
    	ff.write(temp)
    	ff.close()
    	f.close()
    	
    def restore_tile():
    	f = open('//art/ground/DEEP_SWAMP_02_Cellar/00220021orig.jpg', 'rb')
    	temp = f.read()
    	temptell = f.tell()
    	
    	ff = open('//art/ground/DEEP_SWAMP_02_Cellar/00220021.jpg', 'wb')
    	ff.write(temp)
    	ff.close()
    	f.close()
    5. One complication this creates is that you can't tell which image is displayed just by checking some global variable or something like that. e.g. If you've changed the above image to the 'alt' version, how can you tell this has happened when a player starts a new game? Thus you should also manipulate some file to store this state, and switch the files around as necessary. A suitable host for this kind of check would be script_daemon, since it follows the player around and acts as a global script management system.

    As you can guess, the above image has been changed in-game without restarting, or even changing maps :) (it did require scrolling away from it first, however) It was promptly reverted of course to prevent any diplomatic incidents...

    [​IMG]

    Note: Some care should also be taken as to WHEN this manipulation triggers - you probably don't want it happening while the player is scrolling the view, as a crash might result.

    Another note: Some smart ass player will probably find a way to abuse this and laugh at it (e.g. by loading saves right before the graphics have changed). Or maybe it will happen by accident too. But it's probably worth the once in a while glitch, since it gets updated after scrolling away anyway :)
     

    Attached Files:

Our Host!