MMORPG Tutorial Article 4 Server Side Melee Redux!
by Dreamer · 04/12/2005 (9:25 pm) · 38 comments
If you haven't already done so please start here...
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7514
I really wanted to go back to the old school days of rolling dice to determine hit and miss in melee (think pen and paper RPGs), so here goes.
The heart of our Roll Based Server Side melee is this
server/scripts/commands.cs
And of course the sword.cs from our previous tutorial. add the following to the SwordImage
Now you want to be able to melee with your target so the mouseFire in default.bind.cs this
Thats it for Melee, next up will be a couple an example of a very simple DirectDamage(DD) spell and then we will add a database and start work on the MM part of our MMORPG!
Enjoy!
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7514
I really wanted to go back to the old school days of rolling dice to determine hit and miss in melee (think pen and paper RPGs), so here goes.
The heart of our Roll Based Server Side melee is this
server/scripts/commands.cs
function ServerCmdAutoAttack(%client){
if(%client.getClassName() !$="AIPlayer"){
%tempObj = findObject(%client,$TypeMasks::PlayerObjectType,10,1,0);
%targetObject = %client.getSelectedObject();
%client.Player.AttackOn =1;
echo("Aquiring target");
if(!%client.getSelectedObject()){
MessageClient(%client,'No target','You have no target to attack!');
%client.Player.AttackOn = 0;
}else{
if(%tempObj && %tempObj.getId() == %targetObject.getId()){
if(%targetObject.getDamageLevel() < 100 && %client.Player.getDamageLevel() < 100 && %client.Player.AttackOn == 1){
echo("Recieved order for AutoAttack");
%Msg = "You attack "@%targetObject.getShapeName();
MessageClient(%client,'Attack',%Msg);
echo("Rolling!");
%clientRoll = getRandom(1,32) + %client.Player.Atk;
echo(%client.Player.getShapeName()@": "@%clientRoll);
%targetRoll = getRandom(1,32) + %targetObject.AC;
echo(%targetObject.getShapeName()@": "@%targetRoll);
Melee::Attack(%client.Player);
if(%clientRoll >= %targetRoll){
%BaseDamage = %client.Player.getMountedImage(0).BaseDamage;
if(%BaseDamage < 1){
%BaseDamage = 1;
}
%targetObject.applyDamage(%BaseDamage);
%Msg = "You hit "@%targetObject.getShapeName()@" for "@%client.Player.getMountedImage(0).BaseDamage;
MessageClient(%client,'Attack',%Msg);
}else{
%Msg = "You missed "@%targetObject.getShapeName();
MessageClient(%client,'Missed',%Msg);
}
}
if(%targetObject.getClassName() $="AIPlayer"){
if( %targetObject.getAimObject() != %client.Player){
echo("Target is AI, make sure to setup return of Damage");
%targetObject.setAimObject(%client.Player);
schedule(1000,%targetObject,ServerCmdAutoAttack,%targetObject);
}
}else{
if(!%targetObject.getSelectedObject()){
echo("Target is not AI and does not currently hold a target, setting target");
%targetObject.setSelectedObject(%client);
CommandToClient(%TargetObject,'UpdateTargetDialog','NewTarget',%Client.getshapeName());
}
}
schedule(1000,%targetObject,ServerCmdAutoAttack,%Client);
//%Msg = "You are at "@%client.player.getPosition()@" and your target is at "@%targetObject.getPosition();
//MessageClient(%client,'Location',%Msg);
}else{
MessageClient(%client,'OutOfRange','You are too far away to strike your target');
}
}
}else{
//Functions for AI autoattack!
%tempObj = findObject(%client,$TypeMasks::PlayerObjectType,10,1,1);
%targetObject = %client.getAimObject();
if(%tempObj && %tempObj.getId() == %targetObject.getId()){
if(%targetObject.getDamageLevel() < 100 && %client.getDamageLevel() < 100){
%Msg = %client.getShapeName()@' is attacking you!';
MessageClient(%targetObject,'Attack',%Msg);
Melee::Attack(%client);
%clientRoll = getRandom(1,32) + %client.Atk;
echo(%client.getShapeName()@" Rolled "@%clientRoll);
%targetRoll = getRandom(1,32) + %targetObject.AC;
echo(%targetObject.getShapeName()@" Rolled "@%targetRoll);
if(%clientRoll >= %targetRoll){
%BaseDamage = %client.getMountedImage(0).BaseDamage;
if(%BaseDamage < 1){
%BaseDamage = 1;
}
%targetObject.applyDamage(%BaseDamage);
MessageClient(%targetObject,'Attack',%client.getShapeName()@' hits you for '@%client.getMountedImage(0).BaseDamage);
}else{
MessageClient(%targetObject,'Attack',%client.getShapeName()@' missed!');
}
schedule(2000,%targetObject,ServerCmdAutoAttack,%client);
}
}else{
echo("Too far away from client, moving!");
%client.setMoveDestination(%targetObject.getTransform());
schedule(5000,%targetObject,ServerCmdAutoAttack,%client);
}
}
echo("Leaving AutoAttack");
}Make sure in weapons.cs you add the followingfunction Melee::Attack(%obj){
%actnum = getRandom(1,3);
if(%actnum ==1){
%action = "h1swing";
}
if(%actnum ==2){
%action = "h1slice";
}
if(%actnum == 3){
%action = "h1thrust";
}
if(%actnum < 1 || %actnum >3){
%action = "h1swing";
}
%obj.setActionThread(%action);
}
function WeaponImage::onFireHandToHand(%this, %obj, %slot)
{
Melee::Attack(%obj);
}And of course the sword.cs from our previous tutorial. add the following to the SwordImage
BaseDamage = 5;
Now you want to be able to melee with your target so the mouseFire in default.bind.cs this
function mouseFire(%val)
{
$mvTriggerCount0++;
CommandToServer('AutoAttack');
}Thats it for Melee, next up will be a couple an example of a very simple DirectDamage(DD) spell and then we will add a database and start work on the MM part of our MMORPG!
Enjoy!
#2
04/13/2005 (12:23 am)
all i can say is YAY
#3
*Update! The dependant parts finally got approved!
Start here
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7514
04/13/2005 (7:51 am)
Umm, this resource is part of a 7 part (so far) tutorial, they all build on eachother, so far parts 4 and 5 have posted but 1-3 have not yet been approved, I'm not quite sure why.*Update! The dependant parts finally got approved!
Start here
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7514
#4
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7584
04/13/2005 (9:05 am)
Next Tutorial...http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7584
#6
thanks
04/14/2005 (6:23 pm)
just a quick question, what file do we place the first part of the code?thanks
#7
04/14/2005 (7:21 pm)
im guessing thats starter.fps/server/commands.cs
#8
04/14/2005 (11:07 pm)
Fixed it!
#10
This is my console output when I atempt to attack an NPC using the same datablock as the player. Also note this is after targeting him. In my chat output I get that he is out of range even though I am basicly standing on top of his head!
I have done my best to debug this but I am not really sure whats wrong it all looks ok to me. If you have any ideas please let me know!
05/05/2005 (10:56 am)
keyboard0 input device acquired. We are doing raycast and player =1621 /// RayCast Search /// Object = 2010 435.1 -94.0683 237.127 -0.997493 0.0401098 0.0582988 Object Position = 435.814 -94.1651 235.738 Object Id = 2010 Object Name = /// --------------- /// Aquiring target system/server/scripts/commands.cs (239): Unable to find object: '1' attempting to call function 'getId' Leaving AutoAttack We are doing raycast and player =1621 /// RayCast Search /// Object = 2010 435.092 -94.0779 237.122 -0.995862 0.0599572 0.0682989 Object Position = 435.814 -94.1651 235.738 Object Id = 2010 Object Name = /// --------------- /// Aquiring target system/server/scripts/commands.cs (239): Unable to find object: '1' attempting to call function 'getId' Leaving AutoAttack keyboard0 input device unacquired. keyboard0 input device acquired. *** ENDING MISSION CDROP: 1566 IPX:61726553:697A65005369:26478 Exporting server prefs... Exporting client prefs Exporting client config Exporting server prefs Exporting client prefs Exporting server prefs Shutting down the OpenGL display device... Making the GL rendering context not current... Deleting the GL rendering context... Releasing the device context... Restoring the desktop display settings (1024x768x32)... keyboard0 input device unacquired.
This is my console output when I atempt to attack an NPC using the same datablock as the player. Also note this is after targeting him. In my chat output I get that he is out of range even though I am basicly standing on top of his head!
I have done my best to debug this but I am not really sure whats wrong it all looks ok to me. If you have any ideas please let me know!
#11
Just a side note you will get an out of range message if he is not directly in your line of site, I really need to modify this to do a radius search for range, and then do a line of site check to return something like "You need to face your opponent", I'll place that on my TODO list. Also remember that range is limited to 10 at present if you want to increase your melee attack range
Modify the line above, I've had pretty good luck with values up to about 15 anything more, and you lose alot of the effect.
05/05/2005 (3:34 pm)
From the looks of it, it appears you are not aquiring the target first, go into targeting mode and make sure his Health and Energy bars are displayed in the targetingHUD, then attack.Just a side note you will get an out of range message if he is not directly in your line of site, I really need to modify this to do a radius search for range, and then do a line of site check to return something like "You need to face your opponent", I'll place that on my TODO list. Also remember that range is limited to 10 at present if you want to increase your melee attack range
%tempObj = findObject(%client,$TypeMasks::PlayerObjectType,10,1,0);
Modify the line above, I've had pretty good luck with values up to about 15 anything more, and you lose alot of the effect.
#12
I will try adjusting the range and we will see what happens from there!
05/06/2005 (9:47 am)
The npc is targeted. I have to click him about 100 times to find a "Sweet spot" but his health and energy are being showed with his name. After that I am close enough that the two orcs could probaly kiss and facing him perfectly, and still get the message.I will try adjusting the range and we will see what happens from there!
#13
05/06/2005 (10:01 am)
Just a note changing the range did no good, all my scripts and everything compile with no errors. I am not really sure whats the problem here...
#14
smorey@gmail.com
I'll look at it and see what I can find.
05/06/2005 (11:41 am)
@Issac, run the game, execute trace(1); in the console, target the Orc, get close and left click once, wait about 30 seconds, then exit the game and email your log to...smorey@gmail.com
I'll look at it and see what I can find.
#15
Let me know what you come up with please
05/06/2005 (12:30 pm)
@dreamy, alright did what you said. Thanks for the help!Let me know what you come up with please
#16
I've never recieved it.
05/06/2005 (4:15 pm)
It's been over an hour since you posted this, could you please resend the log?I've never recieved it.
#17
Sorry
05/06/2005 (4:59 pm)
Thats why I hate gmail, I will resend it tommorrw why I am at the office. Sorry
#19
Please let me know if I'm miss reading this. Thanks!
05/24/2005 (1:06 pm)
Wouldn't you want the range for the sword in the sword.cs file so you can accomidate various weapon ranges in the future? Unless I'm reading it wrong all melee weapons end up with the same range currently. I'm thinking that if you added a polearm or halbred in the future you'd need to be able to set the range further out than for the sword.Please let me know if I'm miss reading this. Thanks!
#20
This is something that I believe would be specific to your game implimentation. In other games (NwN for instance) a melee weapon is a melee weapon. They may be longer or shorter but the attack distance required for melee attacks is kept the same. If you were to have the range adjust on a per-melee-weapon basis I would guess that the players would figure this out very quickly and switch to their halibard the moment they see their opponent wielding a sword as the halibard would obvious connect with greater range which in effect would render the "shorter" melee weapons "not-as-good". This is a balance that must be chosen for your game and is not something that can be stated across-the-board as being benificial to everyone.
05/24/2005 (1:44 pm)
@Alan: This is a tutorial and not intended to cover all the bases with implementation and is instead more of a guide or working illustration of the concept. There are many many many aspects of these tutorials that are left as an excercise for the reader. Perhaps the advanced tutorial series that Dreamer is working on will provide more of the concrete work you're looking for. Now to make an attempt at answering your question...Quote:Wouldn't you want the range for the sword in the sword.cs file so you can accomidate various weapon ranges in the future? Unless I'm reading it wrong all melee weapons end up with the same range currently. I'm thinking that if you added a polearm or halbred in the future you'd need to be able to set the range further out than for the sword.
This is something that I believe would be specific to your game implimentation. In other games (NwN for instance) a melee weapon is a melee weapon. They may be longer or shorter but the attack distance required for melee attacks is kept the same. If you were to have the range adjust on a per-melee-weapon basis I would guess that the players would figure this out very quickly and switch to their halibard the moment they see their opponent wielding a sword as the halibard would obvious connect with greater range which in effect would render the "shorter" melee weapons "not-as-good". This is a balance that must be chosen for your game and is not something that can be stated across-the-board as being benificial to everyone.
Torque Owner Josh Moore