Folks,
me again with YAI (yet another issue) that I have not been able to wrap my arms fully around to and could use a kick in the right direction. It involves melee combat and on-line games. What we did is something a bit different. We got away from using the trace X units in front of a player and went to an animation driven system. We created a dozen or so custom attack animations for the pawn class( one handed swings, two handed, jabs/pokes, ect). We look at your movement and the base the attack animation on the movement. The key is the weapon and how its attached. We use one standard bone in the model to attach to your hand. Then we placed 2 bones in the model of the weapon. We place one of them at the tip of the blade and the other in the hilt of a sword (for example). Then we the player "fires" the weapon, we start tracing between these two points. As soon something breaks that trace we look at the hit detection to see if it was a "wall", a player or another weapon (ie a block) then handle that hit. The system works pretty well off-line. However on-line its a different story and I am sure its how I set up the replication of the weapons. Instead of using a started weapon attachment I used this:
No real reason why I chose to make this a parent of Actor. What should I have used for the parent of the MeleeWeapon Class? So in on-line games it does not do any damage. And some time the sword will attach it self to the players hands. It depends on the bReplicateMovement var. If I leave it in as false, then my sword attachment spawns but its is never attached to my hand. Thus I walk around with out a weapon. If I remove it (so its set to true via the Actor class setting) then my weapon gets attached. However when I log the location of the trace joints they never move. So I can not hit anything. Now with some work I was able to play on-line with the bots. I noticed that when the swords did not attach (ie bReplicateMovement=false) I would see these swords lying at their spawns. If I walked up to a bots sword and that bot swung, then I DID TAKE damage. So the method will work. Once I can figure out what I did wrong. I guess I don't understand how it can attach the weapon and yet not have the sword joints be updated. Any thoughts???
me again with YAI (yet another issue) that I have not been able to wrap my arms fully around to and could use a kick in the right direction. It involves melee combat and on-line games. What we did is something a bit different. We got away from using the trace X units in front of a player and went to an animation driven system. We created a dozen or so custom attack animations for the pawn class( one handed swings, two handed, jabs/pokes, ect). We look at your movement and the base the attack animation on the movement. The key is the weapon and how its attached. We use one standard bone in the model to attach to your hand. Then we placed 2 bones in the model of the weapon. We place one of them at the tip of the blade and the other in the hilt of a sword (for example). Then we the player "fires" the weapon, we start tracing between these two points. As soon something breaks that trace we look at the hit detection to see if it was a "wall", a player or another weapon (ie a block) then handle that hit. The system works pretty well off-line. However on-line its a different story and I am sure its how I set up the replication of the weapons. Instead of using a started weapon attachment I used this:
Code:
//==================================================================
// The active weapon file
//==================================================================
class swordAttachmentb extends MeleeWeapon placeable;
var ShieldSparks Sparks;
var(Health) float Health;
var() int MomentumTransfer;
var() float damMomentum; // changed type to float from int -jm
var() int Damage;
var() int DamageRadius;
var() int DamageType;
var swipetrail SweepTrail;
var() float HeadShotDamageMult;
var() float HeadShotRadius;
var name ActionAttack;
var array<Actor> HitActors[16]; // this array will keep our list of hit actors.
// Sounds vars
var(MeleeSounds) array<Sound> BlockSound;
var(MeleeSounds) array<Sound> Melee_HitFlesh;
var(MeleeSounds) array<Sound> Melee_HitArmor;
var(MeleeSounds) array<Sound> Head_Shot;
var Sound HitWallSound;
//=============================================================================
// PostBeginPlay
// Set up the swipe effects
//=============================================================================
simulated function PostBeginPlay()
{
local actor W;
W = self;
// log("I am here " @location);
//Log("My instigator is " @instigator.controller.Playerreplicationinfo.PlayerName);
if ( Level.NetMode != NM_DedicatedServer)
{
if (!Level.bDropDetail && (Level.DetailMode != DM_Low) )
SweepTrail = Spawn(class 'swipetrail', self);
if ( SweepTrail != None )
{
W.AttachToBone(SweepTrail, 'sweepjoint3');
SweepTrail.mRegen =false;
}
}
}
//=============================================================================
// ThirdPersonEffects
// Blank out any current 3rd person effects
//=============================================================================
simulated event ThirdPersonEffects()
{
}
//=============================================================================
// Explode
// Blows up with an effect?
// Jb: Why? for like a shattered sword???? Hmm Come back and remove later?
//=============================================================================
simulated function Explode(vector HitLocation, vector HitNormal)
{ // is this used? - JM
if (Role == ROLE_Authority)
{
// HurtRadius(Damage, DamageRadius, class'ketoweapons.DamTypesever',
// MomentumTransfer, HitLocation );
}
if (EffectIsRelevant(Location, false))
Spawn(class 'ImpactDust',,, Location); // ,rotator(Velocity));
}
//=============================================================================
// Destroyed
// Remove the swipe/sparks effect
//=============================================================================
simulated function Destroyed()
{
if (SweepTrail != None)
sweeptrail.Destroy();
if (Sparks != None)
Sparks.Destroy();
Super.Destroyed();
}
//=============================================================================
// CheckHit
// Remove the swipe/sparks effect
//=============================================================================
function bool CheckHit(Actor A)
{
local int i;
// Check if this actor is valid to be struck
if(A == Owner || A.Owner == Owner || A == self)
{
return false;
}
// Check this actor against the HitCount array
for(i = 0; i < 16; i++)
{
if(HitActors[i]== A)
{ // Found this actor in the list
return false;
}
}
// The actor wasn't in the list, so add it
for(i = 0; i < 16; i++)
{
if(HitActors[i] == None)
{
HitActors[i]= A;
return true;
}
}
return(false);
}
//=============================================================================
// ClearHitActors
// Resets the array of actors we hit
//=============================================================================
function ClearHitActors()
{
local int i;
for(i = 0; i < 16; i++)
HitActors[i] = None;
}
//=============================================================================
// Timer
// This function checks to see if any object passes between the sweep joints of
// the weapon.
//
// Jb: AdHOCK (or is that AdHACK...hehheh get it...hahaha) fix was to move it to a timer and have the
// fire class controlls when the timer as active and not active....hey its a bit better...
//=============================================================================
Function Timer()
{
local vector newpos1;
local vector newpos2;
local coords newcoords1;
local coords newcoords2;
local Vector End, HitLocation, HitNormal, Start;
local actor Other;
local actor W;
// local xWeaponAttachment WeaponAttachment;
local Weapon Weapon;
local Controller C;
if (SweepTrail != None)
SweepTrail.mRegen = true;
W = self; // say my name...
newcoords1 = W.GetBoneCoords('sweepjoint1'); // get the location of the sword blade start
newcoords2 = W.GetBoneCoords('sweepjoint2'); // get the location of the sword blade end
newpos1 = newcoords1.Origin;
newpos2 = newcoords2.Origin;
log("sweep joints are at " @newpos1 @newpos2);
MeleePawn(Instigator).pt1 = newcoords1.Origin;
MeleePawn(Instigator).pt2 = newcoords2.Origin; // copy for async trace drawing
Start = newpos1;
End = newpos2;
Other = Trace(HitLocation, HitNormal, End, Start, true); // see if the sword 'line' hits anything
C = Instigator.Controller;
Weapon = Instigator.Weapon;
if (Other != None && Other != W )
{
if (Other.IsA('MeleeWeapon'))
{
PlaySound(BlockSound[Rand(BlockSound.Length)], SLOT_Interact);
if (CheckHit(Other))
{
// Hit a new object here..spawn effect
Spawn(class 'WallSparks',,, HitLocation);
}
// We also should stop our swing...as we are not swining amy more.
// Cad do this by setting the bfire tag to false, then play another
// animation to stop
// Jb: Stop their fire
if (C != none)
{
C.bFire = 0;
Weapon.StopFire(0); // now we need to stop the player from holding the firebutton down
}
// Reset thier animation
ActionAttack = '2hstance';
MeleePawn(Instigator).SetAnimAction(ActionAttack);
SwordFire(Weapon.FireMode[0]).GotoState(''); // Stop the swing!
// moved gotostate to the end, in case it was jumpin early. -jm
}
else if (Other.bWorldGeometry)
{
// weve struck map stuff
PlaySound(HItWallSound, SLOT_Interact);
if (CheckHit(Other))
{
Spawn(class'HitEffect'.static.GetHitEffect(Other, Other.Location,HitNormal)
,,, HitLocation, Rotator(HitNormal));
}
if (C != none)
{
C.bFire = 0;
Weapon.StopFire(0); // now we need to stop the player from holding the firebutton down
}
// Reset their animation
ActionAttack = '2hstance';
MeleePawn(Instigator).SetAnimAction(ActionAttack);
// on the surface type (like rune did)
SwordFire(Weapon.FireMode[0]).GotoState(''); // Stop the swing!
}
else if (Other.IsA('Projectile'))
{
// Maybe play a custom sound for projectiles here??
// call that projeciles ProcessTouch to see if it can be refelected
Projectile(Other).ProcessTouch(Instigator, HitLocation);
}
else if (!Other.bWorldGeometry && Other != Instigator && Other != Owner && Other.IsA('Pawn'))
{
// we hit paydirt! err, it hit the other pawn in the flesh, time to do some damage.
// Jb: Maybe put a check for a team mate and if so stop the swing or damage?
//Play sounds here
if (Pawn(Other).ShieldStrength != 0.0)
PlaySound(Melee_HitArmor[Rand(Melee_HitArmor.Length)], SLOT_Interact); // implies hit a target with shield/armor
else
PlaySound(Melee_HitFlesh[Rand(Melee_HitFlesh.Length)], SLOT_Interact); // implies hit a target with w/o shield/armor
// give them damage :)
ProcessTouch(Other, HitLocation);
}
}
// else
// {
if (SweepTrail != None)
SweepTrail.mRegen = false;
// }
}
//=============================================================================
// ProcessTouch
// Call when we hit another actor to see if we should hand out damage.
//=============================================================================
simulated function ProcessTouch(Actor Other, Vector hitLocation)
{
local Vector X, moe;
local float dist;
local class<DamageType> swordDamageType;
if (Other == Instigator)
return;
if (Other == Owner)
return;
if (Other == self)
return;
Damage = Default.Damage + (5*Sword(Instigator.Weapon).CurrentStance);
// if the current pawn is in berserk mode, increase their damage by 20%
if ( Instigator.IsA('xPawn') && xPawn(Instigator).CurrentCombo != none && xPawn(Instigator).CurrentCombo.IsA('ComboBerserk'))
Damage += Damage * 0.20;
if (Other != None && Other.IsA('xPawn') )
{
X = Normal(Other.Location-Instigator.location);
moe = (X+vect(0,0,0.5))*damMomentum;
// collect damagetype from custom weapons
if ( Instigator.Weapon.IsA( 'Sword' ) )
swordDamageType = class 'DamTypeSword';
else if ( Instigator.Weapon.IsA( 'Axe' ) )
swordDamageType = class 'DamTypeAxe';
else
swordDamageType = class 'DamTypeDoubleAxe';
if (Pawn(Other) != None)
{
if (Other.GetClosestBone(HitLocation, X, dist, 'head', HeadShotRadius) == 'head')
{
PlaySound(Head_Shot[Rand(Head_Shot.Length)], SLOT_Interact);
Other.TakeDamage(Damage * HeadShotDamageMult,Instigator, HitLocation, moe, class 'Melee.DamTypeseverHead ');
}
else
{
Other.TakeDamage(Damage, Instigator, HitLocation, moe, swordDamageType );
}
}
}
else if (Other != None && Other.bProjTarget)
{
Other.TakeDamage(Damage, Instigator, HitLocation, moe, swordDamageType );
// Need a sound for a reflect/projectile hit?? Or No solid hits?
PlaySound(HitWallSound, SLOT_Misc);
}
}
defaultproperties
{
Health=500;
MomentumTransfer=30000;
damMomentum=25000f;
HeadShotDamageMult=2.000000;
HeadShotRadius=8.000000;
Damage=15;
DamageRadius=45;
DrawType=DT_Mesh;
// Temp add by Jb
Mesh=SkeletalMesh'Chaos_melee1.OldBastardSword'
DrawScale=0.425
// end temp
SurfaceType=EST_Metal;
SoundRadius=100.000000;
SoundVolume=255;
TransientSoundVolume=1.200000;
TransientSoundRadius=400.000000;
bCollideActors=True;
bCollideWorld=True;
bBlockActors=True;
bBlockPlayers=True;
// added in these to better model the sword
CollisionRadius=6;
CollisionHeight=41;
BlockSound(0)=Sound'MeleeSounds.Melee.sword_blockmelee1'
BlockSound(1)=Sound'MeleeSounds.Melee.sword_blockmelee2'
BlockSound(2)=Sound'MeleeSounds.Melee.sword_blockmelee3'
BlockSound(3)=Sound'MeleeSounds.Melee.sword_blockmelee4'
BlockSound(4)=Sound'MeleeSounds.Melee.sword_blockmelee6'
BlockSound(5)=Sound'MeleeSounds.Melee.sword_blockmelee5'
HitWallSound=Sound'MeleeSounds.Melee.sword_wall1'
Melee_HitFlesh(0)=Sound'MeleeSounds.Melee.melee_hitflesh1'
Melee_HitFlesh(1)=Sound'MeleeSounds.Melee.melee_hitflesh2'
Melee_HitFlesh(2)=Sound'MeleeSounds.Melee.melee_hitflesh3'
Melee_HitFlesh(3)=Sound'MeleeSounds.Melee.melee_hitflesh4'
Melee_HitFlesh(4)=Sound'MeleeSounds.Melee.melee_hitflesh5'
Melee_HitFlesh(5)=Sound'MeleeSounds.Melee.melee_hitflesh6'
Melee_HitFlesh(6)=Sound'MeleeSounds.Melee.melee_hitflesh7'
Melee_HitFlesh(7)=Sound'MeleeSounds.Melee.melee_hitflesh8'
Melee_HitArmor(0)=Sound'MeleeSounds.Melee.melee_hitarmor1'
Melee_HitArmor(1)=Sound'MeleeSounds.Melee.melee_hitarmor2'
Melee_HitArmor(2)=Sound'MeleeSounds.Melee.melee_hitarmor3'
Melee_HitArmor(3)=Sound'MeleeSounds.Melee.melee_hitarmor4'
Melee_HitArmor(4)=Sound'MeleeSounds.Melee.melee_hitarmor5'
Melee_HitArmor(5)=Sound'MeleeSounds.Melee.melee_hitarmor6'
Head_Shot(0)=Sound'MeleeSounds.Melee.melee_headshot1'
Head_Shot(1)=Sound'MeleeSounds.Melee.melee_headshot2'
Head_Shot(2)=Sound'MeleeSounds.Melee.melee_headshot3'
Head_Shot(3)=Sound'MeleeSounds.Melee.melee_headshot4'
Head_Shot(4)=Sound'MeleeSounds.Melee.melee_headshot5'
}
and its partent:
[code]
//============================================================
// base class for the weapon "attachments"
//============================================================
class MeleeWeapon extends Actor;
defaultproperties
{
bCollideActors=True;
bCollideWorld=True;
bBlockActors=True;
bBlockPlayers = true;
bPathColliding = False;
//Replication stuff
bGameRelevant=True;
bAlwaysRelevant=True
//bReplicateMovement=false
}
No real reason why I chose to make this a parent of Actor. What should I have used for the parent of the MeleeWeapon Class? So in on-line games it does not do any damage. And some time the sword will attach it self to the players hands. It depends on the bReplicateMovement var. If I leave it in as false, then my sword attachment spawns but its is never attached to my hand. Thus I walk around with out a weapon. If I remove it (so its set to true via the Actor class setting) then my weapon gets attached. However when I log the location of the trace joints they never move. So I can not hit anything. Now with some work I was able to play on-line with the bots. I noticed that when the swords did not attach (ie bReplicateMovement=false) I would see these swords lying at their spawns. If I walked up to a bots sword and that bot swung, then I DID TAKE damage. So the method will work. Once I can figure out what I did wrong. I guess I don't understand how it can attach the weapon and yet not have the sword joints be updated. Any thoughts???
Last edited: