UE1 - UT What would it take to get this weapon to work online?

  • Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

Rajada

Member
Jan 21, 2008
213
0
16
rajada.tumblr.com
It is supposed to with alt-fire fire a detonatable grenade (by pressing alt fire again). Works perfect in singleplayer but does not detonate in multiplayer. Any ideas? This came with the game, I'm just trying to make another version of it that works online.

Weapon:

Code:
class MightyMo expands NerfWeapon;

replication
{
	// Things the client should send to the server
	reliable if ( Role<ROLE_Authority )
		DetBall;
}

function timer()
{
if(DetBall == none)
bAltFireOff = False;
}
function float RateSelf( out int bUseAltMode )
{
	local float EnemyDist;
	local bool bRetreating;
	local vector EnemyDir;

	//TraceLog(class, 10, "in RateSelf(...)");

	if (AmmoType.AmmoAmount <=0)
		return -2;
	if (Pawn(Owner).Enemy == None)
	{
		bUseAltMode = 0;
		return AIRating;
	}

	EnemyDir = Pawn(Owner).Enemy.Location - Owner.Location; 
	EnemyDist = VSize(EnemyDir);
	if ( EnemyDist < 270 )
	{
		bUseAltMode = 0;
		return -0.1;
	}

	if ( EnemyDist < -1.5 * EnemyDir.Z )
		bUseAltMode = int( FRand() < 0.5 );
	else if ( Pawn(Owner).Location.Z < Pawn(Owner).Enemy.Location.Z )
		bUseAltMode = 0;
	else
	{
		bRetreating = ( ((EnemyDir/EnemyDist) Dot Owner.Velocity) < -0.7 );
		bUseAltMode = 0;
		if ( ((EnemyDist < 600) || (bRetreating && (EnemyDist < 800)))
			&& (FRand() < 0.4) )
			bUseAltMode = 1;
	}
	return AIRating;
}

// return delta to combat style
function float SuggestAttackStyle()
{
	local float EnemyDist;

	//TraceLog(class, 10, "in SuggestAttackStyle()");

	EnemyDist = VSize(Pawn(Owner).Enemy.Location - Owner.Location);
	if ( EnemyDist < 400 )
		return -0.6;
	else
		return -0.2;
}

function setHand(float Hand)
{
	local rotator newRot;

	Super.SetHand(Hand);
	if ( Hand == 1 )
		Mesh = Mesh(DynamicLoadObject("NerfWeapon.MML", class'Mesh'));
	else if ( Hand == -1 )
		Mesh = Mesh'MMR';
	else
	{
		PlayerViewOffset.Y = 0;
		FireOffset.Y = 0;
		bHideWeapon = true;
	}
}
function DropFrom(vector StartLocation)
{
	bCanClientFire = false;
		bAltFireOff = False;
		DestroyBall();
		DetBall = none;
	bSimFall = true;
	if ( !SetLocation(StartLocation) )
		return; 
	AIRating = Default.AIRating;
	bMuzzleFlash = 0;
	if ( AmmoType != None )
	{
		PickupAmmoCount = AmmoType.AmmoAmount;
		AmmoType.AmmoAmount = 0;
	}
	RespawnTime = 0.0; //don't respawn
	SetPhysics(PHYS_Falling);
	RemoteRole = ROLE_DumbProxy;
	BecomePickup();
	NetPriority = 2.5;
	bCollideWorld = true;
	if ( Pawn(Owner) != None )
		Pawn(Owner).DeleteInventory(self);
	GotoState('PickUp', 'Dropped');
}

///////////////////////////////////////////////////////
function AltFire( float Value )
{
//	log(class$ " WES: DetBall" @DetBall);
	if(( DetBall == None) && (!bDetBall) && (!bAltFireOff))
	{
		bPointing=True;

//			log(class$ " WES: goto altfiring state");
			GoToState( 'AltFiring' );
	}
	else
	{
//		log(class$ " WES: Human Destroy");
		if( !Owner.IsA( 'NerfBots' ) )
		{
			DestroyBall();
		}
	}
}


simulated function DestroyBall()
{
//	log(class$ " WES: Explode in DestroyBall function");
	if(DetBall != none)
	DetBall.explode( DetBall.Location + Vect( 0, 0, 1 ) * 16, Normal(DetBall.Location + Vect( 0, 0, 1 ) * 16));
	PlayDetAnim();
	bAltFireOff = True;
	SetTimer(0.25,false);
	DetBall = None;
}
State DownWeapon
{
ignores Fire, AltFire, AnimEnd;

	function BeginState()
	{
		Super.BeginState();
		bCanClientFire = false;
		DestroyBall();
	}
}
state AltFiring
{
ignores AltFire, PutDown, DropFrom;
	
	function Fire(float F) 
	{
//		log(class$ " WES: fire at altfiring state");
	}

	function BeginState()
	{
		local vector FireLocation, StartLoc, X, Y, Z;
		local float Angle;
						
//		log(class$ " WES: goto altfiring beginstate");
		if( bDetBall && Owner.IsA( 'NerfBots' ) )
		{
			GotoState( 'Idle' );
		}
		GetAxes( Pawn( Owner ).ViewRotation, X , Y, Z );
		StartLoc = Owner.Location + CalcDrawOffset(); 
		FireLocation = StartLoc + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z; 
		Firelocation = StartLoc - 10.78*Z + X * (10 + 8 * FRand());
	
		AdjustedAim = Pawn( Owner ).AdjustToss( AltProjectileSpeed, FireLocation, AimError, True, bAltWarnTarget );	
		if( PlayerPawn( Owner ) != None )
		{
			AdjustedAim = Pawn( Owner ).ViewRotation;
		}

//		log(class$ " WES: create DetBall");
	if(AmmoType.UseAmmo(1))
	{
		DetBall = Spawn( class 'MMDetBall',, '', FireLocation, AdjustedAim );
		DetBall.Launcher = Self;
		bAltFireOff = False;
		PlayAltFiring();
	}	

		if( PlayerPawn(Owner) != None )
		{
			PlayerPawn( Owner ).ShakeView( ShakeTime, ShakeMag * 1.5, ShakeVert * 1.5 ); 
		}
//		log(class$ " WES: Seting Player Altfire button to none" @Pawn(Owner).bAltFire);
		Pawn( Owner ).bAltFire = 0;
		//Disable( 'Tick' );

//		log(class$ " WES: pause for half second" );
		
		//SetTimer( 0.25, false );

	}
	simulated function Timer()
	{
		GotoState( 'Idle' );
	}
	
	simulated function Tick( float DeltaTime )
	{
//		log(class$ " WES: Ticking Altfire button down?" @Pawn(Owner).bAltFire);
		//if( Pawn( Owner ).bAltFire != 0 )
		//{
//			log(class$ " WES: Altfire button down. Explode" @Pawn(Owner).bAltFire);
		//	DetBall.explode( DetBall.Location , Vect( 0, 0, 1 ));
		//	DetBall = None;
		//	bDetBall= False;
		//	Disable( 'Tick' );
		//}
	}
							
Begin:
	FinishAnim();
	Sleep( 0.5 );
	Finish();
}

///////////////////////////////////////////////////////
simulated function PlayFiring()
{
	Owner.PlaySound(FireSound, SLOT_Misc,Pawn(Owner).SoundDampening);
	PlayAnim('fire', 1.0, 0.05);
	
		if(bArenaMode)
	AmmoType.AmmoAmount = 999;
}

///////////////////////////////////////////////////////
simulated function PlayAltFiring()
{
	Owner.PlaySound(AltFireSound, SLOT_Misc,Pawn(Owner).SoundDampening);
	PlayAnim('fire', 0.75, 0.05);
	
		if(bArenaMode)
	AmmoType.AmmoAmount = 999;
}


///////////////////////////////////////////////////////
simulated function PlayDetAnim()
{
	if(!bAltFireOff)
	{
	PlayAnim('idle',1.0,0.05);
	}
}
///////////////////////////////////////////////////////
simulated function PlayIdleAnim()
{
	PlayAnim('idle',0.25,0.05);
}
///////////////////////////////////////////////////////////

function Projectile ProjectileFire(class<projectile> ProjClass, float ProjSpeed, bool bWarn)
{
	local Vector Start, X,Y,Z;
	local Pawn PawnOwner;

	PawnOwner = Pawn(Owner);
	Owner.MakeNoise(PawnOwner.SoundDampening);
	GetAxes(PawnOwner.ViewRotation,X,Y,Z);
	Start = Owner.Location + CalcDrawOffset() + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z; 
	AdjustedAim = PawnOwner.AdjustToss(ProjSpeed, Start, AimError, True, bWarn);	
	return Spawn(ProjClass,,, Start,AdjustedAim);	
}

Projectile (pri and parent):

Code:
class MMBall expands Projectile;

var bool bCanHitOwner, bHitWater;
var int TimeSpan;

auto state Flying
{

	simulated function ZoneChange( Zoneinfo NewZone )
	{
		local waterring w;
	
		if (!NewZone.bWaterZone || bHitWater) Return;
		bHitWater = True;
		Disable('Tick');
		if ( Level.NetMode != NM_DedicatedServer )
		{
			w = Spawn(class'WaterRing',,,,rot(16384,0,0));
			w.DrawScale = 0.2;
			w.RemoteRole = ROLE_None;
		}		
		Velocity=0.6*Velocity;
	}


	simulated function ProcessTouch (Actor Other, Vector HitLocation)
	{
		if ((Other != instigator) || bCanHitOwner ) 
			Explode(HitLocation,Normal(HitLocation-Other.Location));
	}

	function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
						Vector momentum, name damageType)
	{
		Explode(HitLocation,Normal(HitLocation));
	}


	simulated function Timer()
	{
		Explode(Location,Vect(0,0,1));
	}

	function BlowUp(vector HitLocation)
	{
		HurtRadius(damage, 150, MyDamageType, MomentumTransfer, HitLocation);
		MakeNoise(1.0);
	}

	simulated function HitWall( vector HitNormal, actor Wall )
	{
		bCanHitOwner = True;
		Velocity = 0.8*(( Velocity dot HitNormal ) * HitNormal * (-2.0) + Velocity);   // Reflect off Wall w/damping
		RandSpin(100000);
		speed = VSize(Velocity);

		if (Wall != None)
			Wall.TakeDamage(0, Instigator, Location, Vect(0,0,0), 'shot');

		if ( Level.NetMode != NM_DedicatedServer )
			PlaySound(ImpactSound, SLOT_Misc, FMax(0.5, speed/800) );
		if ( Velocity.Z > 400 )
			Velocity.Z = 0.5 * (400 + Velocity.Z);	
		else if ( speed < 60 ) 
		{
			bBounce = False;
			SetPhysics(PHYS_Falling);
			GotoState('BombTicking');
/*
			Speed=0;
			SetTimer(TimeSpan, false);
*/
		}
	}

	simulated function Landed( vector HitNormal )
	{
		HitWall( HitNormal, None );
	}

	simulated function Explode(vector HitLocation, vector HitNormal)
	{
		local MightyMExp s;

		BlowUp(HitLocation);
		s = spawn(class'MightyMExp',,,HitLocation + HitNormal*16 );	
		s.RemoteRole = ROLE_None;
		PlaySound(MiscSound, SLOT_None, 2.3);	
		Destroy();
	}

	simulated function BeginState()
	{
		local rotator RandRot;
		local vector InitialDir;

		bCanHitOwner = False;
		initialDir = vector(Rotation);	
		Velocity = speed*initialDir;
		Velocity.z += 210;
		Velocity = Velocity >> RandRot;
		RandSpin(50000);	
		if (Region.Zone.bWaterZone)
		{
			bHitWater = True;
			Velocity=0.6*Velocity;
		}
	}
}

State BombTicking
{

	simulated function ProcessTouch (Actor Other, Vector HitLocation)
	{
		Explode(HitLocation,Normal(HitLocation-Other.Location));
	}

	function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
						Vector momentum, name damageType)
	{
		Explode(HitLocation,Normal(HitLocation));
	}


	simulated function Timer()
	{
		Explode(Location,Vect(0,0,1));
	}

	function BlowUp(vector HitLocation)
	{
		HurtRadius(damage, 150, MyDamageType, MomentumTransfer, HitLocation);
		MakeNoise(1.0);
	}

	simulated function Explode(vector HitLocation, vector HitNormal)
	{
		local MightyMExp s;

		BlowUp(HitLocation);
		s = spawn(class'MightyMExp',,,HitLocation + HitNormal*16 );	
		s.RemoteRole = ROLE_None;
		PlaySound(MiscSound, SLOT_None, 2.3);	
		Destroy();
	}

	function BeginState()
	{
		Speed=0;
		SetTimer(TimeSpan, false);
	}

}

Projectile (alt):

Code:
class MMDetBall expands MMBall;

//var bool Det;
var MightyMo Launcher;

/*
replication
{
	// Things the server should send to the client.
	unreliable if( Role==ROLE_Authority )
		Det;
}


simulated function Tick( float DeltaTime )
{
	if (Det)
	{
		Disable('Tick');
		Explosion(Location);
	}
}
*/

auto state Flying
{
	function BeginState()
	{
		Super.BeginState();
		if ( (Level.NetMode != NM_Standalone) && (Role == ROLE_Authority) )
		{
			if (PlayerPawn(Instigator) != None) 
				RemoteRole = ROLE_SimulatedProxy;
			else
				RemoteRole = ROLE_AutonomousProxy;
		}
	}
	simulated function Explode(vector HitLocation, vector HitNormal)
	{
		local MightyMExp s;

		BlowUp(HitLocation);
		s = spawn(class'MightyMExp',,,HitLocation + HitNormal*16 );	
		s.RemoteRole = ROLE_None;
		PlaySound(MiscSound, SLOT_None, 2.3);
		if(launcher != none)
		{
		Launcher.bDetBall= False;
		Launcher.DetBall = none;	
		}	
		Destroy();
	}

}
State BombTicking
{
	simulated function Explode(vector HitLocation, vector HitNormal)
	{
		local MightyMExp s;

		BlowUp(HitLocation);
		s = spawn(class'MightyMExp',,,HitLocation + HitNormal*16 );	
		s.RemoteRole = ROLE_None;
		PlaySound(MiscSound, SLOT_None, 2.3);
		if(launcher != none)
		{
		Launcher.bDetBall= False;	
		Launcher.DetBall = none;
		}	
		Destroy();
	}
}
 
Last edited:

gopostal

Active Member
Jan 19, 2006
848
47
28
You don't show what you are subclassing. You need to look there to make sure the other variables are replicated properly.
 

gopostal

Active Member
Jan 19, 2006
848
47
28
I don't mean to sound like a tard but that doesn't really help. Those are custom, without those classes I can't follow anything.

You need to follow the chain back and find where the last replication is that works and then move forward. This could get pretty involved, depending on how much custom work there is (and I'm betting it is a lot).
 

Rajada

Member
Jan 21, 2008
213
0
16
rajada.tumblr.com
Yes, but isn't there at least some work that could be found in the weapon and projectiles themselves? Like simulating functions and re-adding replication? NerfWeapon is pretty identical to a class like UnrealWeapon and projectile is as it was in Unreal. I thought the work would lie only in the replication of this particular weapon.
 
Last edited:

gopostal

Active Member
Jan 19, 2006
848
47
28
The answer is a big 'maybe'. A lot depends on how they built replication in their base classes. You can't extend something if it isn't there, and if it isn't there you'll have to work back and add it. I'd start with "projectile" or whatever passes for it in your gametype. Look at the values the base class replicates then follow them to your class.

My guess (for what it's worth) is that some code was copied out from the UT stuff and modified. It's easy to miss things or muck them up, especially when you aren't testing for problems with every replicated value.

If it were me I'd start logging replication and see what's really good and what isn't.
 

Rajada

Member
Jan 21, 2008
213
0
16
rajada.tumblr.com
By setting the alt projectile to be not bNetTemporary it now explodes online. It does damage, however the explosion is invisible, so that will be my next task.
 

War_Master

Member
May 27, 2005
702
0
16
Make sure the projectile is set to ROLE_SimulatedProxy since it is set to ROLE_DumbProxy by default. If you don't set it to be simulated then the simulated functions won't be replicated.
 

Zur

surrealistic mad cow
Jul 8, 2002
11,708
8
38
48
Make sure the projectile is set to ROLE_SimulatedProxy since it is set to ROLE_DumbProxy by default. If you don't set it to be simulated then the simulated functions won't be replicated.

Does ROLE_SimulatedProxy mean that the projectile movement is handled by the client?
 

gopostal

Active Member
Jan 19, 2006
848
47
28
Raj, I apologize I hadn't thought about this: Did you use WotGreal to export the source code out to work on things? If you did it sometimes sets defaultproperties to numerical value and you have to go back and edit it to proper text.

For instance if you extract the WarShell with Wot you get this
Code:
defaultproperties
{
    speed=600.00
    Damage=1000.00
    MomentumTransfer=100000
    MyDamageType=RedeemerDeath
    ExplosionDecal=Class'NuclearMark'
    bNetTemporary=False
    RemoteRole=2                                <------------------See this?
    AmbientSound=Sound'Redeemer.WarFly'
    Mesh=LodMesh'missile'
    AmbientGlow=78
    bUnlit=True
    SoundRadius=100
    SoundVolume=255
    CollisionRadius=15.00
    CollisionHeight=8.00
    bProjTarget=True
}

and you need to edit it so it reads:
Code:
RemoteRole=ROLE_SimulatedProxy

because the numerical value sometimes is just ignored or doesn't work. I have no idea why it does sometimes and not others but I've learned to check every defprop I copy into code and I keep a cheat sheet of what the numbers correspond to. Several properties will do this so keep an eye out for them and if this is wrong in your base code you need to fix it to get your replication on track.