it's just as simple as I describe.

I literately combined idbobber & idrotater together.
/*
===============================================================================
idRotater aka func_funkytown by thf 8/28/19
===============================================================================
*/
CLASS_DECLARATION( idMover_Periodic, idRotater )
EVENT( EV_Activate, idRotater::Event_Activate )
END_CLASS
/*
===============
idRotater::idRotater
===============
*/
idRotater::idRotater( void ) {
activatedBy = this;
}
/*
===============
idRotater::Spawn
===============
*/
void idRotater::Spawn( void ) {
physicsObj.SetSelf( this );
physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
physicsObj.SetAxis( GetPhysics()->GetAxis() );
physicsObj.SetClipMask( MASK_SOLID );
if ( !spawnArgs.GetBool( "nopush" ) ) {
physicsObj.SetPusher( 0 );
}
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, gameLocal.time, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin );
physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, GetPhysics()->GetAxis().ToAngles(), ang_zero, ang_zero );
SetPhysics( &physicsObj );
if ( spawnArgs.GetBool( "start_on" ) ) {
ProcessEvent( &EV_Activate, this );
}
//idbobber added by thf 8/28/19
float bob_speed;
float height;
float phase;
bool x_axis;
bool y_axis;
idVec3 delta;
spawnArgs.GetFloat("bob_speed", "4", bob_speed);
spawnArgs.GetFloat("height", "32", height);
spawnArgs.GetFloat("phase", "0", phase);
spawnArgs.GetBool("bob_x_axis", "0", x_axis);
spawnArgs.GetBool("bob_y_axis", "0", y_axis);
// set the axis of bobbing
delta = vec3_origin;
if (x_axis) {
delta[0] = height;
}
else if (y_axis) {
delta[1] = height;
}
else {
delta[2] = height;
}
physicsObj.SetSelf(this);
physicsObj.SetClipModel(new idClipModel(GetPhysics()->GetClipModel()), 1.0f);
physicsObj.SetOrigin(GetPhysics()->GetOrigin());
physicsObj.SetAxis(GetPhysics()->GetAxis());
physicsObj.SetClipMask(MASK_SOLID);
if (!spawnArgs.GetBool("nopush")) {
physicsObj.SetPusher(0);
}
physicsObj.SetLinearExtrapolation(extrapolation_t(EXTRAPOLATION_DECELSINE | EXTRAPOLATION_NOSTOP), phase * 1000, bob_speed * 500, GetPhysics()->GetOrigin(), delta * 2.0f, vec3_origin);
SetPhysics(&physicsObj);
}
/*
===============
idRotater::Save
===============
*/
void idRotater::Save( idSaveGame *savefile ) const {
activatedBy.Save( savefile );
}
/*
===============
idRotater::Restore
===============
*/
void idRotater::Restore( idRestoreGame *savefile ) {
activatedBy.Restore( savefile );
}
/*
===============
idRotater::Event_Activate
===============
*/
void idRotater::Event_Activate( idEntity *activator ) {
float rot_speed;
bool rot_x_axis;
bool rot_y_axis;
idAngles delta;
activatedBy = activator;
delta.Zero();
if ( !spawnArgs.GetBool( "rotate" ) ) {
spawnArgs.Set( "rotate", "1" );
spawnArgs.GetFloat( "rot_speed", "100", rot_speed );
spawnArgs.GetBool( "rot_x_axis", "0", rot_x_axis );
spawnArgs.GetBool( "rot_y_axis", "0", rot_y_axis );
// set the axis of rotation
if ( rot_x_axis ) {
delta[2] = rot_speed;
} else if ( rot_y_axis ) {
delta[0] = rot_speed;
} else {
delta[1] = rot_speed;
}
} else {
spawnArgs.Set( "rotate", "0" );
}
physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, physicsObj.GetAxis().ToAngles(), delta, ang_zero );
}