void CAIVehicle::PlayerFrob( idPlayer *player ) { idVec3 origin; idMat3 axis; // =============== DISMOUNT =============== if( m_Controller.GetEntity() ) { if( m_Controller.GetEntity() == player ) { player->Unbind(); SetController( NULL ); } } // =============== MOUNT =============== else { // attach player to the joint GetJointWorldTransform( m_RideJoint, gameLocal.time, origin, axis ); // put the player in a crouch, so their view is low to the animal // without actually clipping into it idPhysics_Player *playerPhys = ( idPhysics_Player * ) player->GetPhysics(); // TODO: look up PMF_DUCKED somehow (make those flags statics in the idPhysics_Player class?) // for now, using 1 since we know that is PMF_DUCKED // Or, we could move mount and dismount to idPhysics_Player... playerPhys->SetMovementFlags( playerPhys->GetMovementFlags() | 1 ); player->SetOrigin( origin + m_RideOffset * axis ); player->BindToJoint( this, m_RideJoint, true ); SetController( player ); } }
/* ===================== rvMonsterStroggHover::UpdateLightDef ===================== */ void rvMonsterStroggHover::UpdateLightDef ( void ) { if ( jointHeadlight != INVALID_JOINT ) { idVec3 origin; idMat3 axis; if ( jointHeadlightControl != INVALID_JOINT ) { idAngles jointAng; jointAng.Zero(); jointAng.yaw = 10.0f * sin( ( (gameLocal.GetTime()%2000)-1000 ) / 1000.0f * idMath::PI ); jointAng.pitch = 7.5f * sin( ( (gameLocal.GetTime()%4000)-2000 ) / 2000.0f * idMath::PI ); animator.SetJointAxis( jointHeadlightControl, JOINTMOD_WORLD, jointAng.ToMat3() ); } GetJointWorldTransform ( jointHeadlight, gameLocal.time, origin, axis ); //origin += (localOffset * axis); // Include this part in the total bounds // FIXME: bounds are local //parent->AddToBounds ( worldOrigin ); //UpdateOrigin ( ); if ( lightHandle != -1 ) { renderLight.origin = origin; renderLight.axis = axis; gameRenderWorld->UpdateLightDef( lightHandle, &renderLight ); } } }
void idActor::Attach( idEntity *ent ) { #if 0 idVec3 origin; noMat3 axis; jointHandle_t joint; idStr jointName; idAttachInfo &attach = attachments.Alloc(); idAngles angleOffset; idVec3 originOffset; jointName = ent->spawnArgs.GetString( "joint" ); joint = animator.GetJointHandle( jointName ); if ( joint == INVALID_JOINT ) { gameLocal.Error( "Joint '%s' not found for attaching '%s' on '%s'", jointName.c_str(), ent->GetClassname(), name.c_str() ); } angleOffset = ent->spawnArgs.GetAngles( "angles" ); originOffset = ent->spawnArgs.GetVector( "origin" ); attach.channel = animator.GetChannelForJoint( joint ); GetJointWorldTransform( joint, gameLocal.time, origin, axis ); attach.ent = ent; ent->SetOrigin( origin + originOffset * renderEntity.axis ); noMat3 rotate = angleOffset.ToMat3(); noMat3 newAxis = rotate * axis; ent->SetAxis( newAxis ); ent->BindToJoint( this, joint, true ); ent->cinematic = cinematic; #endif }
/* ================ sdClientAnimated::Event_GetJointPos returns the position of the joint in worldspace ================ */ void sdClientAnimated::Event_GetJointPos( jointHandle_t jointnum ) { idVec3 offset; idMat3 axis; if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) { offset.Zero(); gameLocal.Warning( "Joint # %d out of range on client entity '%s'", jointnum, GetName() ); } sdProgram::ReturnVector( offset ); }
/* ================ hhWeaponAutoCannon::Ticker ================ */ void hhWeaponAutoCannon::Ticker() { idVec3 boneOriginL, boneOriginR; idMat3 boneAxisL, boneAxisR; if( beamSystem.IsValid() ) { GetJointWorldTransform( sparkBoneL, boneOriginL, boneAxisL ); GetJointWorldTransform( sparkBoneR, boneOriginR, boneAxisR ); if( (boneOriginL - boneOriginR).Length() > sparkGapSize ) { if( !beamSystem->IsHidden() ) { beamSystem->Hide(); SetShaderParm( SHADERPARM_MODE, 0.0f ); } } else if ( owner->CanShowWeaponViewmodel() ) { if( beamSystem->IsHidden() ) { beamSystem->Show(); SetShaderParm( SHADERPARM_MODE, 1.0f ); } } beamSystem->SetOrigin( boneOriginL ); beamSystem->SetTargetLocation( boneOriginR ); } }
/* ================ rvMonsterBerserker::Frame_ChargeGroundImpact ================ */ stateResult_t rvMonsterBerserker::Frame_ChargeGroundImpact ( const stateParms_t& parms ) { idVec3 start; idVec3 end; idMat3 axis; trace_t tr; GetJointWorldTransform ( animator.GetJointHandle ( "R_lowerArm_Real" ), gameLocal.time, start, axis ); end = start; end.z -= 128; // RAVEN BEGIN // ddynerman: multiple clip worlds gameLocal.TracePoint ( this, tr, start, end, MASK_SHOT_BOUNDINGBOX, this ); // RAVEN END gameLocal.PlayEffect ( gameLocal.GetEffect( spawnArgs, "fx_ground_impact" ), tr.endpos, idVec3(0,0,1).ToMat3() ); return SRESULT_OK; }
/* ================ rvMonsterBerserker::Frame_DoBlastAttack ================ */ stateResult_t rvMonsterBerserker::Frame_DoBlastAttack ( const stateParms_t& parms ) { float i; idVec3 start; idMat3 axis; idAngles angles ( 0.0f, move.current_yaw, 0.0f ); const idDict* blastDict; blastDict = gameLocal.FindEntityDefDict ( spawnArgs.GetString ( "def_attack_spike" ), false ); if ( !blastDict ) { gameLocal.Error ( "missing projectile on spike attack for AI entity '%s'", GetName ( ) ) ; return SRESULT_OK; } GetJointWorldTransform ( animator.GetJointHandle ( "end_spike" ), gameLocal.time, start, axis ); for( i = 0; i < 32; i++ ) { angles.yaw += (360.0f / 32.0f); AttackProjectile ( blastDict, start, angles ); } return SRESULT_OK; }
/* ================ rvVehicleAnimated::Think ================ */ void rvVehicleAnimated::Think ( void ) { rvVehicle::Think(); float rate = 0.0f; usercmd_t& cmd = positions[0].mInputCmd; idVec3 delta; if( positions[0].IsOccupied() && !IsFrozen() && IsMovementEnabled() ) { if (( g_vehicleMode.GetInteger() == 0 && !( cmd.buttons & BUTTON_STRAFE )) || // If we're in the old driving mode and we aren't strafing or... ( g_vehicleMode.GetInteger() != 0 && ( cmd.buttons & BUTTON_STRAFE ))) // If we're in the new driving mode and we are strafing { rate = SignZero(cmd.forwardmove) * turnRate; rate *= idMath::MidPointLerp( 0.0f, 0.9f, 1.0f, idMath::Fabs(cmd.rightmove) / 127.0f ); viewAngles.yaw += Sign(cmd.rightmove) * rate * MS2SEC(gameLocal.GetMSec()); } } viewAngles.Normalize360(); animator.GetDelta( gameLocal.time - gameLocal.GetMSec(), gameLocal.time, delta ); delta += additionalDelta; idStr alignmentJoint; if ( g_vehicleMode.GetInteger() != 0 && spawnArgs.GetString( "alignment_joint", 0, alignmentJoint ) ) { idVec3 offset; idMat3 axis; GetJointWorldTransform( animator.GetJointHandle( alignmentJoint ), gameLocal.time, offset, axis ); delta *= axis; } else { viewAxis = viewAngles.ToMat3() * physicsObj.GetGravityAxis(); delta *= viewAxis; } physicsObj.SetDelta( delta ); additionalDelta.Zero(); }
/* ================ idTestModel::Think ================ */ void idTestModel::Think() { idVec3 pos; idMat3 axis; idAngles ang; int i; if( thinkFlags & TH_THINK ) { if( anim && ( gameLocal.testmodel == this ) && ( mode != g_testModelAnimate.GetInteger() ) ) { StopSound( SND_CHANNEL_ANY, false ); if( head.GetEntity() ) { head.GetEntity()->StopSound( SND_CHANNEL_ANY, false ); } switch( g_testModelAnimate.GetInteger() ) { default: case 0: // cycle anim with origin reset if( animator.NumFrames( anim ) <= 1 ) { // single frame animations end immediately, so just cycle it since it's the same result animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); if( headAnim ) { headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); } } else { animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); if( headAnim ) { headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); if( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) { // loop the body anim when the head anim is longer animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 ); } } } animator.RemoveOriginOffset( false ); break; case 1: // cycle anim with fixed origin animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); animator.RemoveOriginOffset( true ); if( headAnim ) { headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); } break; case 2: // cycle anim with continuous origin animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); animator.RemoveOriginOffset( false ); if( headAnim ) { headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); } break; case 3: // frame by frame with continuous origin animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); animator.RemoveOriginOffset( false ); if( headAnim ) { headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); } break; case 4: // play anim once animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); animator.RemoveOriginOffset( false ); if( headAnim ) { headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); } break; case 5: // frame by frame with fixed origin animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); animator.RemoveOriginOffset( true ); if( headAnim ) { headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); } break; } mode = g_testModelAnimate.GetInteger(); } if( ( mode == 0 ) && ( gameLocal.time >= starttime + animtime ) ) { starttime = gameLocal.time; StopSound( SND_CHANNEL_ANY, false ); animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); if( headAnim ) { headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); if( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) { // loop the body anim when the head anim is longer animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 ); } } } if( headAnimator ) { // copy the animation from the body to the head for( i = 0; i < copyJoints.Num(); i++ ) { if( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) { idMat3 mat = head.GetEntity()->GetPhysics()->GetAxis().Transpose(); GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis ); pos -= head.GetEntity()->GetPhysics()->GetOrigin(); headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat ); headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat ); } else { animator.GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis ); headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos ); headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis ); } } } // update rotation RunPhysics(); physicsObj.GetAngles( ang ); physicsObj.SetAngularExtrapolation( extrapolation_t( EXTRAPOLATION_LINEAR | EXTRAPOLATION_NOSTOP ), gameLocal.time, 0, ang, idAngles( 0, g_testModelRotate.GetFloat() * 360.0f / 60.0f, 0 ), ang_zero ); idClipModel* clip = physicsObj.GetClipModel(); if( clip != NULL && animator.ModelDef() ) { idVec3 neworigin; idMat3 axis; jointHandle_t joint; joint = animator.GetJointHandle( "origin" ); animator.GetJointTransform( joint, gameLocal.time, neworigin, axis ); neworigin = ( ( neworigin - animator.ModelDef()->GetVisualOffset() ) * physicsObj.GetAxis() ) + GetPhysics()->GetOrigin(); clip->Link( gameLocal.clip, this, 0, neworigin, clip->GetAxis() ); } } UpdateAnimation(); Present(); if( ( gameLocal.testmodel == this ) && g_showTestModelFrame.GetInteger() && anim ) { gameLocal.Printf( "^5 Anim: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n", animator.AnimFullName( anim ), animator.CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ), animator.CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - animator.CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) ); if( headAnim ) { gameLocal.Printf( "^5 Head: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n\n", headAnimator->AnimFullName( headAnim ), headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ), headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) ); } else { gameLocal.Printf( "\n\n" ); } } }
/* ================ rvMonsterRepairBot::UpdateRepairs ================ */ void rvMonsterRepairBot::UpdateRepairs ( repairBotArm_t& arm ) { trace_t tr; idVec3 origin; idMat3 axis; if ( arm.joint == INVALID_JOINT ) { return; } if ( gameLocal.time > repairEndTime ) { StopRepairs ( arm ) ; return; } // If the repair time has been crossed we need to start/stop the repairs if ( gameLocal.time > arm.repairTime ) { if ( arm.repairing ) { StopRepairs ( arm ); arm.repairTime = gameLocal.time + gameLocal.random.RandomInt ( 500 ); arm.repairing = false; } else { arm.repairTime = gameLocal.time + gameLocal.random.RandomInt ( 2500 ); arm.repairing = true; } } if ( !arm.repairing ) { return; } // Left repair effect GetJointWorldTransform ( arm.joint, gameLocal.time, origin, axis ); gameLocal.TracePoint ( this, tr, origin, origin + axis[0] * repairEffectDist, MASK_SHOT_RENDERMODEL, this ); if ( tr.fraction >= 1.0f ) { StopRepairs ( arm ); } else { // Start the repair effect if not already started if ( !arm.effectRepair ) { arm.effectRepair = PlayEffect ( "fx_repair", arm.joint, true ); } // If the repair effect is running then set its end origin if ( arm.effectRepair ) { arm.effectRepair->SetEndOrigin ( tr.endpos ); } // Start the impact effect if ( !arm.effectImpact ) { arm.effectImpact = PlayEffect ( "fx_repair_impact", tr.endpos, tr.c.normal.ToMat3(), true ); } else { // Calculate the local origin and axis from the given globals idVec3 localOrigin = (tr.endpos - renderEntity.origin) * renderEntity.axis.Transpose ( ); idMat3 localAxis = tr.c.normal.ToMat3 ();// * renderEntity.axis.Transpose(); arm.effectImpact->SetOrigin ( localOrigin ); arm.effectImpact->SetAxis ( localAxis ); } if( gameLocal.GetTime() > arm.periodicEndTime ) {// FIXME: Seems dumb to keep banging on this if the fx isn't defined. gameLocal.PlayEffect( spawnArgs, "fx_repair_impact_periodic", tr.endpos, tr.c.normal.ToMat3() ); arm.periodicEndTime = gameLocal.GetTime() + SEC2MS( rvRandom::flrand(spawnArgs.GetVec2("impact_fx_delay_range", "1 1")) ); } } }
/* ================ rvMonsterStroggHover::Think ================ */ void rvMonsterStroggHover::Think ( void ) { idAI::Think ( ); if ( !aifl.dead ) { // If thinking we should play an effect on the ground under us if ( !fl.hidden && !fl.isDormant && (thinkFlags & TH_THINK ) && !aifl.dead ) { trace_t tr; idVec3 origin; idMat3 axis; // Project the effect 80 units down from the bottom of our bbox GetJointWorldTransform ( jointDust, gameLocal.time, origin, axis ); // RAVEN BEGIN // ddynerman: multiple clip worlds gameLocal.TracePoint ( this, tr, origin, origin + axis[0] * (GetPhysics()->GetBounds()[0][2]+80.0f), CONTENTS_SOLID, this ); // RAVEN END // Start the dust effect if not already started if ( !effectDust ) { effectDust = gameLocal.PlayEffect ( gameLocal.GetEffect ( spawnArgs, "fx_dust" ), tr.endpos, tr.c.normal.ToMat3(), true ); } // If the effect is playing we should update its attenuation as well as its origin and axis if ( effectDust ) { effectDust->Attenuate ( 1.0f - idMath::ClampFloat ( 0.0f, 1.0f, (tr.endpos - origin).LengthFast ( ) / 127.0f ) ); effectDust->SetOrigin ( tr.endpos ); effectDust->SetAxis ( tr.c.normal.ToMat3() ); } // If the hover effect is playing we can set its end origin to the ground /* if ( effectHover ) { effectHover->SetEndOrigin ( tr.endpos ); } */ } else if ( effectDust ) { effectDust->Stop ( ); effectDust = NULL; } //Try to circle strafe or pursue if ( circleStrafing ) { CircleStrafe(); } else if ( !inPursuit ) { if ( !aifl.action && move.fl.done && !aifl.scripted ) { if ( GetEnemy() ) { if ( DistanceTo( GetEnemy() ) > 2000.0f || (GetEnemy()->GetPhysics()->GetLinearVelocity()*(GetEnemy()->GetPhysics()->GetOrigin()-GetPhysics()->GetOrigin())) > 1000.0f ) {//enemy is far away or moving away from us at a pretty decent speed TryStartPursuit(); } } } } else { Pursue(); } //Dodge if ( !circleStrafing ) { if( combat.shotAtTime && gameLocal.GetTime() - combat.shotAtTime < 1000.0f ) { if ( nextBombFireTime < gameLocal.GetTime() - 3000 ) { if ( gameLocal.random.RandomFloat() > evadeChance ) { //40% chance of ignoring it - makes them dodge rockets less often but bullets more often? combat.shotAtTime = 0; } else if ( evadeDebounce < gameLocal.GetTime() ) { //ramps down from 400 to 100 over 1 second float speed = evadeSpeed - ((((float)(gameLocal.GetTime()-combat.shotAtTime))/1000.0f)*(evadeSpeed-(evadeSpeed*0.25f))); idVec3 evadeVel = viewAxis[1] * ((combat.shotAtAngle >= 0)?-1:1) * speed; evadeVel.z *= 0.5f; move.addVelocity += evadeVel; move.addVelocity.Normalize(); move.addVelocity *= speed; /* if ( move.moveCommand < NUM_NONMOVING_COMMANDS ) { //just need to do it once? combat.shotAtTime = 0; } */ if ( evadeDebounceRate > 1 ) { evadeDebounce = gameLocal.GetTime() + gameLocal.random.RandomInt( evadeDebounceRate ) + (ceil(((float)evadeDebounceRate)/2.0f)); } } } } } //If using melee rush to nav to him, stop when we're close enough to attack if ( combat.tacticalCurrent == AITACTICAL_MELEE && move.moveCommand == MOVE_TO_ENEMY && !move.fl.done && nextBombFireTime < gameLocal.GetTime() - 3000 && enemy.fl.visible && DistanceTo( GetEnemy() ) < 2000.0f ) { StopMove( MOVE_STATUS_DONE ); ForceTacticalUpdate(); } else { //whenever we're not in the middle of something, force an update of our tactical if ( !aifl.action ) { if ( !aasFind ) { if ( move.fl.done ) { if ( !inPursuit && !circleStrafing ) { ForceTacticalUpdate(); } } } } } } //update light // if ( lightOn ) { UpdateLightDef ( ); // } }