#using scripts\shared\ai_shared; #using scripts\shared\math_shared; #using scripts\shared\sound_shared; #using scripts\shared\throttle_shared; #using scripts\shared\util_shared; #using scripts\shared\ai\systems\debug; #using scripts\shared\ai\systems\init; #using scripts\shared\ai\archetype_utility; #using scripts\shared\ai\systems\weaponList; #using_animtree("generic"); function autoexec main() { level.ai_weapon_throttle = new Throttle(); [[ level.ai_weapon_throttle ]]->Initialize( 1, 0.1 ); } function private _throwStowedWeapon( entity, weapon, weaponModel ) { entity waittill( "death" ); if(IsDefined(entity)) { weaponModel Unlink(); entity shared::ThrowWeapon( weapon, getTagForPos( "back" ), false ); } weaponModel Delete(); } function StowWeapon( weapon, positionOffset, orientationOffset ) { entity = self; if ( !IsDefined( positionOffset ) ) { positionOffset = (0, 0, 0); } if ( !IsDefined( orientationOffset ) ) { orientationOffset = (0, 0, 0); } weaponModel = Spawn( "script_model", (0, 0, 0) ); weaponModel SetModel( weapon.worldmodel ); weaponModel LinkTo( entity, "tag_stowed_back", positionOffset, orientationOffset ); entity thread _throwStowedWeapon( entity, weapon, weaponModel ); } function placeWeaponOn( weapon, position ) { self notify("weapon_position_change"); if ( IsString( weapon ) ) { weapon = GetWeapon( weapon ); } if (!isdefined(self.weaponInfo[weapon.name])) self init::initWeapon( weapon ); curPosition = self.weaponInfo[weapon.name].position; // make sure we're not out of sync assert( curPosition == "none" || self.a.weaponPos[curPosition] == weapon ); if ( !IsArray( self.a.weaponPos ) ) { self.a.weaponPos = []; } assert( IsArray( self.a.weaponPos ) ); assert( position == "none" || IsDefined( self.a.weaponPos[position] ), "Weapon position \"" + position + "\"" ); assert( IsWeapon( weapon ) ); // weapon already in place if ( position != "none" && self.a.weaponPos[position] == weapon ) return; //println("detach all (" + weapon.name + ", " + position + ")"); self detachAllWeaponModels(); // detach if we're already in a position if ( curPosition != "none" ) self detachWeapon( weapon ); // nothing more to do if ( position == "none" ) { //println("update(1) all (" + weapon.name + ", " + position + ")"); self updateAttachedWeaponModels(); self AiUtility::setCurrentWeapon( level.weaponNone ); return; } if ( self.a.weaponPos[position] != level.weaponNone ) self detachWeapon( self.a.weaponPos[position] ); // to ensure that the correct tags for the active weapon are used, we need to make sure it gets attached first if ( position == "left" || position == "right" ) { self updateScriptWeaponInfoAndPos( weapon, position ); self AiUtility::setCurrentWeapon(weapon); } else { self updateScriptWeaponInfoAndPos( weapon, position ); } self updateAttachedWeaponModels(); // make sure we don't have a weapon in each hand assert( self.a.weaponPos["left"] == level.weaponNone || self.a.weaponPos["right"] == level.weaponNone ); } function detachWeapon( weapon ) { self.a.weaponPos[self.weaponInfo[weapon.name].position] = level.weaponNone; self.weaponInfo[weapon.name].position = "none"; } function updateScriptWeaponInfoAndPos( weapon, position ) { self.weaponInfo[weapon.name].position = position; self.a.weaponPos[position] = weapon; } function detachAllWeaponModels() { if( isdefined(self.weapon_positions) ) { for ( index = 0; index < self.weapon_positions.size; index++ ) { weapon = self.a.weaponPos[self.weapon_positions[index]]; if ( weapon == level.weaponNone ) continue; self SetActorWeapon( level.weaponNone, self GetActorWeaponOptions() ); } } } function updateAttachedWeaponModels() { if( isdefined(self.weapon_positions) ) { for ( index = 0; index < self.weapon_positions.size; index++ ) { weapon = self.a.weaponPos[self.weapon_positions[index]]; if ( weapon == level.weaponNone ) continue; // weapon should only be assigned (means self.weapon will be set) to the weapon if its set to go to "right" if( self.weapon_positions[index] != "right" ) continue; self SetActorWeapon( weapon, self GetActorWeaponOptions() ); if ( self.weaponInfo[weapon.name].useClip && !self.weaponInfo[weapon.name].hasClip ) self hidepart( "tag_clip" ); } } } function getTagForPos( position ) { switch ( position ) { case "chest": return "tag_weapon_chest"; case "back": return "tag_stowed_back"; case "left": return "tag_weapon_left"; case "right": return "tag_weapon_right"; case "hand": return "tag_inhand"; default: assertMsg( "unknown weapon placement position: " + position ); break; } } function ThrowWeapon( weapon, positionTag, scavenger ) { waitTime = 0.1; linearScalar = 2.0; angularScalar = 10; // Calculate the linear and angular velocity to launch the weapon. startPosition = self GetTagOrigin( positionTag ); startAngles = self GetTagAngles( positionTag ); // Wait two server frames to calculate velocity. wait( waitTime ); if ( IsDefined( self ) ) { endPosition = self GetTagOrigin( positionTag ); endAngles = self GetTagAngles( positionTag ); linearVelocity = ( endPosition - startPosition ) * ( 1.0 / waitTime ) * linearScalar; angularVelocity = VectorNormalize( endAngles - startAngles ) * angularScalar; throwWeapon = self DropWeapon( weapon, positionTag, linearVelocity, angularVelocity, scavenger ); if ( IsDefined( throwWeapon ) ) { throwWeapon SetContents( throwWeapon SetContents( 0 ) & ~( (1 << 15) | (1 << 26) | (1 << 23) | (1 << 25) ) ); } return throwWeapon; } } function DropAIWeapon() { self endon("death"); if( self.weapon == level.weaponNone ) { return; } if (( isdefined( self.script_nodropsecondaryweapon ) && self.script_nodropsecondaryweapon ) && (self.weapon == self.initial_secondaryweapon)) { /#PrintLn("Not dropping secondary weapon '" + self.weapon.name + "'");#/ return; } else if (( isdefined( self.script_nodropsidearm ) && self.script_nodropsidearm ) && (self.weapon == self.sidearm)) { /#PrintLn("Not dropping sidearm '" + self.weapon.name + "'");#/ return; } [[ level.ai_weapon_throttle ]]->WaitInQueue( self ); current_weapon = self.weapon; dropWeaponName = player_weapon_drop( current_weapon ); position = self.weaponInfo[ current_weapon.name ].position; shouldDropWeapon = !IsDefined( self.dontDropWeapon ) || self.dontDropWeapon === false; if( current_weapon.isScavengable == false ) { shouldDropWeapon = false; } if ( shouldDropWeapon && self.dropWeapon ) { self.dontDropWeapon = true; positionTag = getTagForPos( position ); ThrowWeapon( dropWeaponName, positionTag, false ); } if ( self.weapon != level.weaponNone ) { shared::placeWeaponOn( current_weapon, "none" ); if( self.weapon == self.primaryweapon ) { self AiUtility::setPrimaryWeapon( level.weaponNone ); } else if( self.weapon == self.secondaryweapon ) { self AiUtility::setSecondaryWeapon( level.weaponNone ); } } self AiUtility::setCurrentWeapon( level.weaponNone ); } function DropAllAIWeapons() { if (( isdefined( self.a.dropping_weapons ) && self.a.dropping_weapons )) { // already called return; } if( !self.dropweapon ) { if( self.weapon != level.weaponNone ) { shared::placeWeaponOn( self.weapon, "none" ); self AiUtility::setCurrentWeapon( level.weaponNone ); } return; } self.a.dropping_weapons = true; self detachAllWeaponModels(); droppedSideArm = false; if( isdefined(self.weapon_positions) ) { for ( index = 0; index < self.weapon_positions.size; index++ ) { weapon = self.a.weaponPos[ self.weapon_positions[ index ] ]; if ( weapon != level.weaponNone ) { self.weaponInfo[ weapon.name ].position = "none"; self.a.weaponPos[ self.weapon_positions[ index ] ] = level.weaponNone; if (( isdefined( self.script_nodropsecondaryweapon ) && self.script_nodropsecondaryweapon ) && (weapon == self.initial_secondaryweapon)) { /#PrintLn("Not dropping secondary weapon '" + weapon.name + "'");#/ } else if (( isdefined( self.script_nodropsidearm ) && self.script_nodropsidearm ) && (weapon == self.sidearm)) { /#PrintLn("Not dropping sidearm '" + weapon.name + "'");#/ } else { velocity = self GetVelocity(); speed = Length( velocity ) * 0.5; weapon = player_weapon_drop(weapon); droppedWeapon = self DropWeapon( weapon, self.weapon_positions[ index ], speed ); if ( self.sideArm != level.weaponNone ) { if ( weapon == self.sideArm ) droppedSideArm = true; } } } } } if( !droppedSideArm && self.sideArm != level.weaponNone ) { // 10% chance of dropping sidearm if( RandomInt(100) <= 10 ) { velocity = self GetVelocity(); speed = Length( velocity ) * 0.5; droppedWeapon = self DropWeapon( self.sideArm, "chest", speed ); } } self AiUtility::setCurrentWeapon( level.weaponNone ); self.a.dropping_weapons = undefined; } function player_weapon_drop( weapon ) { if ( IsSubStr( weapon.name, "rpg" ) ) { return GetWeapon( "rpg_player" ); } return weapon; } function HandleNoteTrack( note, flagName, customFunction, var1 ) { } // DoNoteTracks waits for and responds to standard noteTracks on the animation, returning when it gets an "end" or a "finish" // For level scripts, a pointer to a custom function should be passed as the second argument, which handles notetracks not // already handled by the generic function. This call should take the form DoNoteTracks(flagName,&customFunction); // The custom function will be called for each notetrack not recognized, and will pass the notetrack name. Note that this // function could be called multiple times for a single animation. function DoNoteTracks( flagName, customFunction, debugIdentifier, var1 ) // debugIdentifier isn't even used. we should get rid of it. { for (;;) { self waittill (flagName, note); if ( !isdefined( note ) ) { note = "undefined"; } val = self HandleNoteTrack( note, flagName, customFunction, var1 ); if ( isdefined( val ) ) { return val; } } } function DoNoteTracksIntercept( flagName, interceptFunction, debugIdentifier ) // debugIdentifier isn't even used. we should get rid of it. { assert( isdefined( interceptFunction ) ); for (;;) { self waittill ( flagName, note ); if ( !isdefined( note ) ) { note = "undefined"; } intercepted = [[interceptFunction]]( note ); if ( isdefined( intercepted ) && intercepted ) { continue; } val = self HandleNoteTrack( note, flagName ); if ( isdefined( val ) ) { return val; } } } function DoNoteTracksPostCallback( flagName, postFunction ) { assert( isdefined( postFunction ) ); for (;;) { self waittill ( flagName, note ); if ( !isdefined( note ) ) { note = "undefined"; } val = self HandleNoteTrack( note, flagName ); [[postFunction]]( note ); if ( isdefined( val ) ) { return val; } } } // Don't call this function except as a thread you're going to kill - it lasts forever. function DoNoteTracksForever(flagName, killString, customFunction, debugIdentifier) { DoNoteTracksForeverProc(&DoNoteTracks, flagName, killString, customFunction, debugIdentifier); } function DoNoteTracksForeverIntercept(flagName, killString, interceptFunction, debugIdentifier) { DoNoteTracksForeverProc(&DoNoteTracksIntercept, flagName, killString, interceptFunction, debugIdentifier ); } function DoNoteTracksForeverProc( notetracksFunc, flagName, killString, customFunction, debugIdentifier ) { if (isdefined (killString)) { self endon (killString); } self endon ("killanimscript"); if (!isdefined(debugIdentifier)) { debugIdentifier = "undefined"; } for (;;) { time = GetTime(); returnedNote = [[notetracksFunc]](flagName, customFunction, debugIdentifier); timetaken = GetTime() - time; if ( timetaken < 0.05) { time = GetTime(); returnedNote = [[notetracksFunc]](flagName, customFunction, debugIdentifier); timetaken = GetTime() - time; if ( timetaken < 0.05) { /#println (GetTime()+" "+debugIdentifier+" shared::DoNoteTracksForever is trying to cause an infinite loop on anim "+flagName+", returned "+returnedNote+".");#/ wait ( 0.05 - timetaken ); } } //(GetTime()+" "+debugIdentifier+" DoNoteTracksForever returned in "+timetaken+" ms.");#/ } } // Designed for using DoNoteTracks on looping animations, so you can wait for a time instead of the "end" parameter function DoNoteTracksForTime(time, flagName, customFunction, debugIdentifier) { ent = SpawnStruct(); ent thread doNoteTracksForTimeEndNotify(time); DoNoteTracksForTimeProc(&DoNoteTracksForever, time, flagName, customFunction, debugIdentifier, ent); } function DoNoteTracksForTimeIntercept( time, flagName, interceptFunction, debugIdentifier) { ent = SpawnStruct(); ent thread doNoteTracksForTimeEndNotify(time); DoNoteTracksForTimeProc(&DoNoteTracksForeverIntercept, time, flagName, interceptFunction, debugIdentifier, ent); } function DoNoteTracksForTimeProc( doNoteTracksForeverFunc, time, flagName, customFunction, debugIdentifier, ent) { ent endon ("stop_notetracks"); [[doNoteTracksForeverFunc]](flagName, undefined, customFunction, debugIdentifier); } function doNoteTracksForTimeEndNotify(time) { wait (time); self notify ("stop_notetracks"); }