Creating /stance command, Part 3
From Multiverse
| Contributed by: BrianinFairOaks | Last Tested: 02 Apr 08 | Tested By: Brianinfairoaks | Tested With: 1.1 |
| Creating slash stance
|
| Part 1 |
| Part 2 |
| Part 3 |
Now we're almost done!
Right now the player's speed is controlled on the client. In the future this may need to be done differently.
We want to communicate when the 'stance' or 'speed' is changed on the server back to the client. MV already has a way to do this. The client can monitor stats and have a function that will execute when the stat is changed. This is known as event driven programming. To do this we're going to be be modifying the client files. You may have these installed almost anywhere in your development environment. I'm going to refer to them as mvhome/Assets/yourworldname. I have these files installed at c:\multiverse\Assets\sampleworld.
First, locate mvhome/Assets/yourworldname/Interface/FrameXML. This directory contains most of the world specific scripts and code. For reference you can look at MarsUnit.xml, MarsUnit.py, MarsPlayer.xml, and MarsPlayer.py. Create two new files named Stance.py and Stance.xml (I like to copy, paste, and rename existing files). Create the files as follows:
mvhome/Assets/yourworldname/Interface/FrameXML/Stance.xml:
<Ui>
<Script file="Stance.py"/>
<Frame name="StanceFrame"
inherits="MvBasicFrame"
frameStrata="HIGH"
toplevel="true"
movable="true"
hidden="true">
<Scripts language="python">
<OnLoad>
Stance_OnLoad(this)
</OnLoad>
<OnEvent>
Stance_OnEvent(this,args)
</OnEvent>
</Scripts>
</Frame>
</Ui>
The two important elements are the OnLoad and OnEvent entries. These define what code is called when the script is initially executed and then when an event occurs. These functions are in:
mvhome/Assets/yourworldname/Interface/FrameXML/Stance.py:
import MarsUnit
import ClientAPI
def Stance_OnLoad(frame):
ClientAPI.Log("Stance.onLoad")
frame.RegisterEvent("PROPERTY_speed")
def Stance_OnEvent(frame, event):
if (event.eventArgs[0] == "player"):
ClientAPI.Log("Stance.onEvent: " + event.eventType + " args[0] " + str(event.eventArgs[0]) + " speed: " +
str(MarsUnit.UnitSpeed(str(event.eventArgs[0]))))
ClientAPI.InputHandler.PlayerSpeed=MarsUnit.UnitSpeed(str(event.eventArgs[0]))
Be careful that the .Log line is correct when you create this file. It should all be on one line to be safe.
When Stance.xml is loaded it defines Stance.py as the script file. When the MV client sees the OnLoad tag it calls the function defined there. Stance_OnLoad just registers for a change in the Mars Stat 'speed'. Whenever that stat gets changed on the server it is automatically sent to the Client. When the Client see the update it calls the OnLoad event, Stance_OnLoad. This code makes sure that it is the 'player' that is being updated (and not the target or something else) and then it resets the speed.
But what is this MarsUnit.UnitSpeed that is referenced? Did MV already have support for speed already built in? (Probably somewhere, but I didn't use it) This is a new function that we need to add. You might think that it is from the file MarsUnit.py that I reference earlier, but it isn't. In order to confuse you MV gave files in different directories the same name.
We want mvhome/Assets/yourworldname/Scripts/MarsUnit.py. Towards the top of the file add the following code:
def UnitSpeed(unit):
obj = _GetUnit(unit)
return _GetUnitProperty(obj, "speed", 0)
def UnitStance(unit):
obj = _GetUnit(unit)
return _GetUnitProperty(obj, "stance", 1)
While we aren't currently using 'stance' you might want to use it at some point. I like to mark the beginning and ending of my modifications to existing files with comments so that I can find them easier when there is a new release.
Now all we need to do is to cause the two new Stance files to be loaded when the client is started.
mvhome/Assets/yourworldname/Interface/FrameXML/mars.toc (I use Wordpad for this). Go to the bottom of the file and add the line:
Stance.xml
You should now be able to start the servers and log in with your new character and change between sit, walk, and run. While the graphics don't cdurrently change for sit, you should stop moving. There should also be a visible difference in the movement speed between walk and run. You can always tweak the walk and run numbers so that you can verify that they are working.
I think that these files need to be added as Assets via the Asset importer before the client will work to download, but it works locally fine now.
Wrap-up
So why did I make such a complex system to change the player's movement speed when I could have done everything on the client by binding keys in functions? I wanted to have the player's 'stance' effect the game mechanisms and to have the player's stats effect the 'stance' and 'speed'. The only way to do this was to communicate the desired stance to the server and to have the server communicate the results back to the client.
There are many things that you can do to integrate the player's stance into your gameplay mechanics now. Does sitting prevent you from swinging a sword? From dodging a blow? Do mobs aggro on players that are sitting down?
I'm sure that I missed something in this tutorial, or that a future release may break something, or that you might need help with understanding this. Please feel free to ask about this on the forums or to email me at Brian in Fair Oaks (at) Hotmail.com. (Remove the spaces and (at) = @). I'll probably respond faster on the forum than via email (my work blocks Hotmail).
