Script:Files:script/items/landmine.script
From Mod Wiki
/*********************************************************************** item_landmine.script ***********************************************************************/ #define TRIPMINE_RESULT_OK 1 #define TRIPMINE_RESULT_NOT_WALL 2 #define TRIPMINE_RESULT_UNKNOWN_BEAM_RANGE 3 object item_landmine : weapon_base { void preinit(); void init(); void destroy(); void Raise(); void Idle(); void TryAttack( boolean altFire ); void Attack(); boolean CanAltAttack(); void AltAttack(); float CountMines(); void CheckMineLimit(); float CanCreateTripmine(); void ToolTipThread_Raise(); float meleeDistance; float nextToolTipTime; float throwTime; boolean removeOldest; boolean clientAssumeRemoved; boolean clientWait; } void item_landmine::preinit() { meleeDistance = getFloatKey( "melee_distance" ); throwTime = getFloatKeyWithDefault( "throw_time", 0.2 ); } void item_landmine::init() { if ( myPlayer.isLocalPlayer() ) { thread ToolTipThread_Raise(); } weaponState( "Raise", 0 ); } void item_landmine::destroy() { } void item_landmine::Raise() { UpdateCharge(); Base_Raise(); } float item_landmine::CountMines() { return G_CountMinesOwnedByEntity( myPlayer ); } void item_landmine::Idle() { weaponReady(); playCycle( ANIMCHANNEL_ALL, "idle" ); if ( clientWait ) { sys.wait( 0.2f ); clientWait = false; } StartIdleEffect(); if ( ShouldRunGuis() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponShowCharge", 1 ); } mainFireDown = ( WEAPON_ATTACK || WEAPON_ALTFIRE ); while( 1 ) { if( WEAPON_LOWERWEAPON ) { StopIdleEffect(); weaponState( "Lower", 0 ); } if ( WEAPON_ATTACK ) { if( !mainFireDown ) { mainFireDown = true; CheckMineLimit(); TryAttack( false ); } } else if ( WEAPON_ALTFIRE ) { if( !mainFireDown ) { mainFireDown = true; CheckMineLimit(); TryAttack( true ); } } else { mainFireDown = false; } UpdateCharge(); sys.waitFrame(); } } void item_landmine::TryAttack( boolean altFire ) { team_base team = myPlayer.getGameTeam(); float limit = team.GetMineLimit(); if ( CanRemove( chargePerUse ) ) { if ( CountMines() < limit || clientAssumeRemoved ) { removeOldest = false; if ( altFire ) { if ( CanAltAttack() ) { StopIdleEffect(); weaponState( "AltAttack", 0 ); } else { if ( myPlayer == sys.getLocalPlayer() ) { sys.startSoundDirect( getKey( "snd_invalid" ), SND_WEAPON_FIRE_LOCAL ); } } } else { StopIdleEffect(); weaponState( "Attack", 0 ); } } } else { if ( myPlayer == sys.getLocalPlayer() ) { myPlayer.sendToolTip( GetToolTip( getKey( "tt_need_charge" ) ) ); sys.startSoundDirect( getKey( "snd_need_charge" ), SND_WEAPON_FIRE_LOCAL ); G_NotifyNoCharge( myPlayer ); } } } void item_landmine::Attack() { Remove( chargePerUse ); playAnim( ANIMCHANNEL_ALL, "fire" ); fired(); sys.wait( throwTime ); entity mine; if ( !sys.isClient() ) { mine = sys.spawn( getKey( "def_landmine" ) ); mine.vSetOwner( myPlayer ); mine.setGameTeam( myPlayer.getGameTeam() ); boolean placedOnWall = false; vector origin = myPlayer.getViewOrigin(); vector forward = sys.angToForward( myPlayer.getViewAngles() ); float throwDistance = 32.0f; vector throwPos = origin + forward * throwDistance; if( melee( MASK_SHOT_BOUNDINGBOX | MASK_PROJECTILE, meleeDistance, true, false ) ) { float traceDistance = getMeleeFraction() * meleeDistance; float surfaceFlags = getMeleeSurfaceFlags(); vector normal = getMeleeNormal(); entity meleeEntity = getMeleeEntity(); vector endPos = getMeleeEndPos(); string surfaceType = getMeleeSurfaceType(); string joint = getMeleeJoint(); if ( !( surfaceFlags & SURF_NOPLANT ) ) { if ( sys.fabs( normal_z ) < 0.5 ) { placedOnWall = true; if ( meleeEntity != $null_entity ) { vehicle_base meleeVehicle = meleeEntity; if ( meleeVehicle != $null_entity || meleeEntity.vDisablePlantCharge() ) { placedOnWall = false; } } if ( placedOnWall ) { mine.setOrigin( endPos ); mine.alignToAxis( normal, Z_AXIS ); mine.vMakeSticky( meleeEntity, normal, surfaceType, false, joint ); } } } if ( !placedOnWall ) { vector size = mine.getSize(); float pullOut = sys.vecLength( size ) * 0.6f; if ( traceDistance < throwDistance + pullOut ) { throwPos = origin + forward * ( traceDistance - pullOut ); } } } if ( !placedOnWall ) { mine.setOrigin( throwPos ); vector velocity = mine.getVectorKeyWithDefault( "velocity", '400 0 0' ); velocity = forward * velocity_x; mine.setLinearVelocity( velocity ); } } waitUntil( animDone( ANIMCHANNEL_ALL, 0 ) ); if ( !sys.isClient() ) { if ( mine != $null_entity ) { if ( !mine.vGetIsSelfArm() ) { team_base team = myPlayer.getGameTeam(); team.SelectActionItem( myPlayer, AK_ARM ); } myPlayer.setPlayerMineState( mine, false, false ); //mal: let the bots know there is a new landmine out there in the world. } } else { // wait for server to select weapon clientWait = true; } weaponState( "Idle", 0 ); } boolean item_landmine::CanAltAttack() { if ( !melee( MASK_SHOT_BOUNDINGBOX | MASK_PROJECTILE, meleeDistance, true, false ) ) { return false; } float result = CanCreateTripmine(); if ( result == TRIPMINE_RESULT_NOT_WALL || result == TRIPMINE_RESULT_UNKNOWN_BEAM_RANGE ) { string ttString; if ( result == TRIPMINE_RESULT_NOT_WALL ) { ttString = "tt_wrong_surface"; } else if ( result == TRIPMINE_RESULT_UNKNOWN_BEAM_RANGE ) { ttString = "tt_unknown_beam_range"; } if ( myPlayer == sys.getLocalPlayer() ) { myPlayer.cancelToolTips(); sys.wait( 0.1f ); myPlayer.sendToolTip( GetToolTip( getKey( ttString ) ) ); sys.startSoundDirect( getKey( "snd_invalid" ), SND_ANY ); } return false; } return true; } void item_landmine::AltAttack() { entity mine; float result = CanCreateTripmine(); if ( result == TRIPMINE_RESULT_NOT_WALL || result == TRIPMINE_RESULT_UNKNOWN_BEAM_RANGE ) { weaponState( "Idle", 4 ); } entity meleeEntity = getMeleeEntity(); vector normal = getMeleeNormal(); vector point = getMeleePoint(); string surfaceType = getMeleeSurfaceType(); string joint = getMeleeJoint(); Remove( chargePerUse ); playAnim( ANIMCHANNEL_ALL, "fire" ); fired(); sys.wait( throwTime ); if ( !sys.isClient() ) { mine = sys.spawn( getKey( "def_landmine" ) ); mine.vSetOwner( myPlayer ); mine.setGameTeam( myPlayer.getGameTeam() ); mine.setOrigin( point ); mine.alignToAxis( normal, Z_AXIS ); mine.vMakeSticky( meleeEntity, normal, surfaceType, true, joint ); } waitUntil( animDone( ANIMCHANNEL_ALL, 0 ) ); if ( !sys.isClient() ) { if ( mine != $null_entity ) { if ( !mine.vGetIsSelfArm() ) { team_base team = myPlayer.getGameTeam(); team.SelectActionItem( myPlayer, AK_ARM ); } myPlayer.setPlayerMineState( mine, false, false ); //mal: let the bots know there is a new landmine out there in the world. } } weaponState( "Idle", 0 ); } void item_landmine::CheckMineLimit() { team_base team = myPlayer.getGameTeam(); float limit = team.GetMineLimit(); if ( CountMines() >= limit ) { if ( removeOldest ) { myPlayer.RemoveOldestMine(); removeOldest = false; // client assumes mine was removed so as to play the proper fire animation if ( sys.isClient() ) { clientAssumeRemoved = true; } } else { clientAssumeRemoved = false; if ( CanRemove( chargePerUse ) ) { removeOldest = true; if ( myPlayer == sys.getLocalPlayer() ) { myPlayer.cancelToolTips(); sys.wait( 0.1f ); myPlayer.sendToolTip( GetToolTip( getKey( "tt_mine_limit" ) ) ); sys.startSoundDirect( getKey( "snd_invalid" ), SND_WEAPON_FIRE ); } } } } } float item_landmine::CanCreateTripmine() { float traceFraction = getMeleeFraction(); vector normal = getMeleeNormal(); float surfaceFlags = getMeleeSurfaceFlags(); entity meleeEntity = getMeleeEntity(); string surfaceType = getMeleeSurfaceType(); vector endPos = getMeleeEndPos(); float traceDistance = traceFraction * meleeDistance; float result = TRIPMINE_RESULT_OK; if ( !( surfaceFlags & SURF_NOPLANT ) ) { if ( sys.fabs( normal_z ) < 0.5 ) { if ( meleeEntity != $null_entity ) { player meleePlayer = meleeEntity; vehicle_base meleeVehicle = meleeEntity; if ( meleeVehicle != $null_entity || meleePlayer != $null_entity ) { result = TRIPMINE_RESULT_NOT_WALL; } } if( surfaceType == "grass" || surfaceType == "gravel" || surfaceType == "sand" || surfaceType == "dirt" ) { result = TRIPMINE_RESULT_NOT_WALL; } } else { result = TRIPMINE_RESULT_NOT_WALL; } } if ( result == TRIPMINE_RESULT_OK ) { // find trip mine beam distance vector beamStart = endPos; vector beamEnd = beamStart + ( normal * GetGlobalFloat( "tripmine_beam_range" ) ); sys.tracePoint( beamStart, beamEnd, CONTENTS_SOLID | CONTENTS_RENDERMODEL, myPlayer ); if ( sys.getTraceFraction() == 1.f || sys.getTraceEntity() != sys.getEntity( "worldspawn" ) ) { result = TRIPMINE_RESULT_UNKNOWN_BEAM_RANGE; } } return result; } void item_landmine::ToolTipThread_Raise() { myPlayer.cancelToolTips(); sys.wait( myPlayer.CalcTooltipWait() ); WAIT_FOR_TOOLTIP; myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_1" ) ) ); WAIT_FOR_TOOLTIP; myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_2" ) ) ); }