![]() |
|
|
#1 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
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: [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???
__________________
Jb ChaosUT Last edited by jb; 16th Sep 2003 at 01:25 PM. |
|
|
|
|
|
#2 |
|
MSPA
Join Date: Aug. 7th, 2002
Location: The Netherlands (yes, that's Holland)
Posts: 246
|
Why not use InventoryAttachment as base class?
|
|
|
|
|
|
#3 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Daid303,
ok that makes a lot of senses. I made that change but I still do not get any updates to the postion of the sword when I log its location: Code:
log("my postion is " @self.location);
log("sweep joints are at " @newpos1 @newpos2);
__________________
Jb ChaosUT |
|
|
|
|
|
#4 |
|
What if you keep InventoryAttachment as the parent but change "bFastAttachmentReplication" to be false? It might be setting the Actor mostly correct, but I wonder if that var isn't telling the native replication to not worry about sending the location/rotation over the wire.
__________________
_____________________________ I remember old school. Champion of Glaucoma Inducing Radiation Everywhere |
|
|
|
|
|
|
#5 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
RegX,
thanks for the reply. Last night I tried a few things and one of them was as you suggested as well as the bOnlyDirtyReplication. Still no luck. At this point i have no idea why I can see the sword in the hands of my players yet logs show it never moves eventhough I go through the level hopping like a bunny. I would expect if the log is showing it not moving then it would not be attached. Confusing
__________________
Jb ChaosUT |
|
|
|
|
|
#6 |
|
self.location doesn't change, but it's also not 0,0,0 ?
__________________
_____________________________ I remember old school. Champion of Glaucoma Inducing Radiation Everywhere |
|
|
|
|
|
|
#7 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Yeap its set to some non-zero value that I am almost sure its the spawn point of my player (or close to it).
I tried a rather nasty hack of settibg its location every tick to my instigators location. Well I got the logs to show that it moved. However it detached from my hand. I did not figure on a way to reattach it so dropped that idea. Thanks again!
__________________
Jb ChaosUT |
|
|
|
|
|
#8 |
|
This is totally a side note - but is it me, or are semicolons suddenly OK in default props? didn't that use to hose the whole section?
__________________
_____________________________ I remember old school. Champion of Glaucoma Inducing Radiation Everywhere |
|
|
|
|
|
|
#9 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Well I am lazy and will remove them all. Normally spaces are bad in the default section unless you use a semicolon
__________________
Jb ChaosUT |
|
|
|
|
|
#10 |
|
Doing a bit reading, it seems like Role_DumbProxy would be a better choice unless the Owner is acting like a base. ROLE_SimulatedProxy (in inventory attachment) won't replication location if there's no base.
If it is the base, try keeping SimulatedProxy and setting bUpdateSimulatedPosition=True ... (at this point I'm just trying to decipher Actor's replication rules for location)
__________________
_____________________________ I remember old school. Champion of Glaucoma Inducing Radiation Everywhere |
|
|
|
|
|
|
#11 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Thanks I will try that as well as do some more reading on this as well.
__________________
Jb ChaosUT |
|
|
|
|
|
#12 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Reg,
thanks again but still the same results no mater what I try to set its role too....
__________________
Jb ChaosUT |
|
|
|
|
|
#13 | |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Update:
Erik from Epic replied with this: Quote:
__________________
Jb ChaosUT |
|
|
|
|
|
|
#15 |
|
Registered User
Join Date: May. 22nd, 2000
Posts: 278
|
Found a hint burried in the UTMod List.
Basically what I had to do was get the bone cord of the players hands. Move the Attachment class to that location. Set the rotation of the attachment class to that of the right hand. Then reattach. Just 6 lines of code is all it took
__________________
Jb ChaosUT Last edited by jb; 6th Oct 2003 at 09:10 AM. |
|
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|