s1-scripts-dev/raw/maps/mp/_vl_camera.gsc
2025-05-21 16:23:17 +02:00

4471 lines
140 KiB
Plaintext

#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
#include maps\mp\agents\_agent_utility;
//#include maps\mp\bots\_bots_strategy;
#include maps\mp\agents\_scriptedAgents;
#include maps\mp\_vl_base;
LUI_MODE_PRELOBBY = 0;
LUI_MODE_LOBBY = 1;
LUI_MODE_CAC = 2;
LUI_MODE_CAO = 3;
LUI_MODE_OBSCURED = 4; // any menu with background obscuring virtual lobby
LUI_MODE_CLANPROFILE = 5;
OBSTACLE_RADIUS = 16; // 20
OBSTACLE_PATHBIAS = 5; // 10
delayed_luinotifyserver( delay, channel, value )
{
wait delay;
self notify( "luinotifyserver", channel, value );
}
setup_camparams()
{
// Setup the camParams struct which holds all of our camera state and consts
camParams = SpawnStruct();
camParams.TARGETZOFF = 40; // added to target ent's z to get the camera lookat target
camParams.BASEDELTA = 0.25; // Desired distance absolute speed (note we change the desired distance, since pos is determined by the angle)
camParams.tgtDelta = camParams.BASEDELTA; // current signed distance target speed (+- BASEDELTA)
camParams.ACCEL = 0.01; // acceleration used to reach tgtDelta
camParams.delta = 0; // current speed applied to distance
camParams.BASEDANGLE = 0.5; // Desired angle absolute speed
camParams.ANGLEACCEL = 0.01; // acceleration used to reach tgtDAngle
camParams.tgtDAngle = camParams.BASEDANGLE; // current signed angle target speed (+- BASEDANGLE)
camParams.dAngle = 0; // current delta angle
camParams.MAXORBITANGLE = 60; // MAX +- angle from front of character in orbit mode`
camParams.MINORBITDIST = 60; // MIN dist from character in orbit mode
camParams.MAXORBITDIST = 120; // MAX dist from character in orbit mode
camParams.angle = 0; // current angle
camParams.dist = 120; // current distance
camParams.DOF_Time = 12; // speed to transition to new setting
camParams.face_dof_mod = -10; // how many inches away from head bone to focus
camParams.CAOtoLobbyFrameDelay = 3;
camParams.CAOtoLobbyFrameTimer = 0;
/// for group style lobby level
camParams.GAMELOBBYGROUP_CAMOFFSET_ANGLE_RATIO = 0.0; // angle of game lobby camera - ratio of right vector added to camera position ( centered, positive is to right )
camParams.GAMELOBBYGROUP_CAMERAZOFF_ZOOM = 45; // game lobby camera z offset
camParams.GAMELOBBYGROUP_TARGETZOFF_ZOOM = 50; // game lobby camera target z offset
camParams.GAMELOBBYGROUP_CAMERA_OFFSET = 6; // game lobby camera side offset
camParams.GAMELOBBYGROUP_CAMERA_TARGETOFFSET = 6; // game lobby camera target side offset
camParams.GAMELOBBYGROUP_CAMERA_UpCloseZ = 513;
camParams.GAMELOBBYGROUP_CAMERA_NormalZ = 507;
camParams.GAMELOBBYGROUP_CAMERA_CrouchZ = 483;
camParams.GAMELOBBYGROUP_CAMERA_HunchZ = 502;
camParams.GAMELOBBYGROUP_CAMERA_CloseDistance = 71.5;
camParams.GAMELOBBYGROUP_CAMERA_NormalDistance = 96.8;
camParams.GAMELOBBYGROUP_CAMERA_CrouchDistance = 96.8;
camParams.GAMELOBBYGROUP_CAMERA_HunchDistance = 96.8;
camParams.GAMELOBBYGROUP_CAMERA_CrouchThreshold = 490;
camParams.GAMELOBBYGROUP_CAMERA_HunchThreshold = 504.5;
camParams.GAMELOBBYGROUP_CAMERA_NormalThreshold = 509.5;
camParams.GAMELOBBYGROUP_MOVESPEED_MODIFIER = 0.95;
// for cac
camParams.CAC_CAMOFFSET_ANGLE_RATIO = 0.0; // angle of cac camera - ratio of right vector added to camera position ( mostly to the right )
camParams.CAC_CAMERAZOFF_ZOOM = 7; // cac camera z offset
camParams.CAC_TARGETZOFF_ZOOM = 13; // cac camera target z offset
camParams.CAC_CAMERA_OFFSET = 0; // cac camera side offset
camParams.CAC_CAMERA_TARGETOFFSET = 0; // cac camera target side offset
camParams.CAMOFFSET_RATIO_CAC = 0.1; // ratio of right vector added to camera position ( mostly to the right )
camParams.CAC_RATIO_ZOOM = 0.2;
camParams.CAC_FRAMEDELAY = 0;
camParams.CAC_CAMERAZOFF = 17; // cac camera z offset
camParams.CAC_TARGETZOFF = 14.5; // cac camera target z offset
camParams.CAC_DIST = 69;
camParams.CAC_WEAP_OFFSET = 8;
camParams.CAC_WEAP_TUNING = false;
camParams.CAC_WEAP_TUNING_CAMOFFSET = 0;
camParams.CAC_WEAP_TUNING_WEAP_SIDEOFFSET = 0;
camParams.CAC_WEAP_TUNING_WEAP_ZOFFSET = 0;
camParams.CACWeaponDelayTime = 0.35; // delays for coming out of CAC and avatar weapon swapping so it looks cleaner
camParams.CACWeaponAnimDelayTime = 0.1;
camParams.CACWeaponAttachDelayTime = 0.05;
//camParams.cac_weapon_select = false; // currently unused, was used to offset camera
/#
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_enabled", 0 );
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_sideoffset", 0 ); // this is for shifting the weapon before it is linked to weaponpedestal, must respawn weapon and pedestal to see changes, back out of menu then back in
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_weaponPedestal_x", 0 );
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_weaponPedestal_y", 0 );
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_weaponPedestal_z", 0 );
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_MoveModifier", 40 );
SetDevDvarIfUninitialized( "scr_vl_cac_weap_tuning_Ratio", 0.05 );
SetDevDvarIfUninitialized( "scr_vl_anim_choose_anim_enable", 0 );
SetDevDvarIfUninitialized( "scr_vl_anim_index", 0 );
#/
/// for horse shoe style lobby level
camParams.GAMELOBBY_MOVESPEED = 150;
camParams.GAMELOBBY_CAMOFFSET_ANGLE_RATIO = 0.2; // angle of game lobby camera - ratio of right vector added to camera position ( mostly to the right )
camParams.GAMELOBBY_CAMERAZOFF_ZOOM = 45; // game lobby camera z offset
camParams.GAMELOBBY_TARGETZOFF_ZOOM = 55; // game lobby camera target z offset
camParams.GAMELOBBY_CAMERA_OFFSET = 16; // game lobby camera side offset
camParams.GAMELOBBY_CAMERA_TARGETOFFSET = 24; // game lobby camera target side offset
camParams.GAMELOBBY_CAMERA_ROTATION_SPEED = 0.5;
camParams.goal = "avatar";
camParams.GAMELOBBY_CAMERA_CURVE_MODIFY = 0.005;
camParams.GAMELOBBY_CAMERA_CURVE_STOREDY = 0;
camParams.GAMELOBBY_CAMERA_CURVE_MOVEX = 64;
camParams.GAMELOBBY_CAMERA_DEPTH_SCALER = 0;
camParams.tgt_camoffset_ratio = camParams.CAMOFFSET_RATIO_PRELOBBY;
camParams.cur_camoffset_ratio = camParams.tgt_camoffset_ratio;
camParams.cac_camoffset_ratio = 0;
camParams.cac_weap_loot_offset = ( -0.02, 0, -0.08 );
camParams.cac_weap_screen_offset = ( 0.05, 0, -0.06 );
camParams.camoffset_ratio_maxspeed = 0.25;
camParams.CAMZOFF = 10; // 40 // the z applied to the offset from the target to the desired camera position
camParams.MOVESPEED = 150; // units per second
camParams.ANGSPEED = 800; // degrees per second
camParams.prelobbyZoom = 0; // 0,1,2 for zoom distance
rightStick = self GetUnNormalizedCameraMovement();
camParams.oldRotX = rightStick[0];
camParams.oldRotY = rightStick[1];
camParams.zoom = 0.5;
camParams.rotate = 0.5;
camParams.framedelay = 0;
camParams.pre_lobby_framedelay = 4; // delay for when loading lobby or reloading lobby after despawning your avatar so camera doesn't go crazy
camParams.delayed_cut = false;
// SetDepthOfField( 0, 35, 55, 100, 7.5, 3.5); <-- (old values)
// SetDepthOfField( 0, 0, 159.8, 205.59, 7.5, 2); <-- (new values)
camParams.dof_near_start = 0;
camParams.dof_near_end = 0;
camParams.dof_far_start = 159.8;
camParams.dof_far_end = 205.59;
camParams.dof_near_blur = 7.5;
camParams.dof_far_blur = 2;
camParams.origin_offset = (0,0,40);
camParams.PRELOBBY_MOVESPEED = 300;
camParams.PRELOBBY_TARGETZOFF_ZOOM = 10;
camParams.PRELOBBY_TARGETZOFF = 42;
camParams.PRELOBBY_NEARDIST = 40;
camParams.PRELOBBY_FARDIST = 200;
camParams.PRELOBBY_CAMERAZOFF = 0;
camParams.PRELOBBY_CAMERAZOFF_ZOOM = 20;
camParams.PRELOBBY_CAMERA_RATIO = 0.325;
camParams.PRELOBBY_RATIO_ZOOM = 0.2;
camParams.CAMOFFSET_RATIO_LOBBY = -0.1; // ratio of right vector added to camera position for lobby ( slightly left of center )
camParams.CAMOFFSET_RATIO_PRELOBBY = 0.19; // ratio of right vector added to camera position ( mostly to the right )a
camParams.CAMOFFSET_RATIO_PRELOBBY_LOOT = -1;
camParams.CH_CYL_ZOFF_FAR = 36;
camParams.CH_CYL_ZOFF_NEAR = 42;
camParams.transitioning = false;
camParams.CAO_TARGETZOFF_ZOOM = 10;
camParams.CAO_TARGETZOFF = 31;
camParams.CAO_NEARDIST = 40;
camParams.CAO_FARDIST = 200;
camParams.CAO_CAMERAZOFF = 0;
camParams.CAO_CAMERAZOFF_ZOOM = 20;
camParams.CAO_CAMERA_RATIO = 0.77;
camParams.CAO_RATIO_ZOOM = 0.2;
camParams.CAO_CAMOFFSET_RATIO = 0.25; // ratio of right vector added to camera position ( mostly to the right )a
mode = GetDvarInt( "virtualLobbyMode", 0 );
if ( mode == LUI_MODE_PRELOBBY )
{
camParams.mode = "game_lobby"; // getting rid prelobby, we just need gamelobby for avatars nows
start_prelobby_anims();
SetDVar( "virtualLobbyReady", "0" ); // We'll ensure it is false to start with
}
else
{
camParams.mode = "transition"; // orbit, transition, prelobby, startmenu
camParams.tgt_camoffset_ratio = camParams.CAMOFFSET_RATIO_LOBBY;
camParams.cur_camoffset_ratio = camParams.tgt_camoffset_ratio;
start_lobby_anims();
if ( GetDVarInt( "virtualLobbyReady", 0 ) == 0 )
{
SetDVar( "virtualLobbyReady", "1" );
}
if ( mode == LUI_MODE_CAC )
self thread delayed_luinotifyserver( 0.1, "cac", 0 );
else if ( mode == LUI_MODE_CAO )
self thread delayed_luinotifyserver( 0.1, "cao", 0 );
}
camParams.newmode = camParams.mode;
level.camParams = camParams; // so notifies can change it
}
update_camera_params_ratio( camParams )
{
if (isdefined(self.cut))
camParams.cur_camoffset_ratio = camParams.tgt_camoffset_ratio;
else
{
dRatio = camParams.tgt_camoffset_ratio - camParams.cur_camoffset_ratio;
if ( dRatio < -1*camParams.camoffset_ratio_maxspeed )
dRatio = -1*camParams.camoffset_ratio_maxspeed;
else if ( dRatio > camParams.camoffset_ratio_maxspeed )
dRatio = camParams.camoffset_ratio_maxspeed;
camParams.cur_camoffset_ratio += dRatio;
}
}
vlobby_lighting_setup()
{
player = self;
if ( IsDefined( level.vl_lighting_setup ))
player [[ level.vl_lighting_setup ]] ();
else
{
player EnablePhysicalDepthOfFieldScripting();
player SetPhysicalDepthOfField( 0.613159, 89.8318, level.camParams.DOF_Time, level.camParams.DOF_Time );
}
}
Set_Avatar_DOF()
{
if(isdefined(level.camParams.goal))
{
if(level.camParams.goal == "moving" || level.camParams.goal == "finding_new_position" || level.vlavatars[level.vl_focus] != level.vlavatars[level.old_vl_focus])
{
return; // dont update dof
}
}
if(isdefined(level.camParams.camera.cut) && level.camParams.camera.cut == true)
{
return; // dont update dof
}
player = self;
// gettin new camera position instead of old counter rotated camera position
if(IsDefined(level.camParams.camera.goal_location))
{
CamLocation = level.camParams.camera.goal_location;
}
else
{
avatar = level.vlavatars[level.old_vl_focus];
tag_camera_loc_vec3 = avatar GetTagOrigin("TAG_STOWED_BACK");
DistTagToAvatar = Distance2D(tag_camera_loc_vec3, avatar.avatar_spawnpoint.origin);
CamLocationFloor = avatar.avatar_spawnpoint.origin + (AnglesToForward(avatar.avatar_spawnpoint.angles) * DistTagToAvatar);
CamLocation = (CamLocationFloor[0], CamLocationFloor[1], tag_camera_loc_vec3[2]);
}
bCamSHouldUpdate = CheckCamPosition(level.camParams.camera, CamLocation, 1.5);
// find out if we should calculate dof dist from where the camera will be, or where the camera is
if(bCamSHouldUpdate == true)
{
predicted_cam_location = CamLocation;
}
else
{
predicted_cam_location = level.camParams.camera.origin;
}
Cam2TgtDist = distance( level.vlavatars[level.old_vl_focus] GetTagOrigin("j_spine4"), predicted_cam_location);
player vlobby_dof_based_on_focus(Cam2TgtDist + level.camParams.face_dof_mod);
}
vlobby_dof_based_on_focus(Dist)
{
if ( Dist <= 0.0 )
return;
player = self;
dof_time = level.camParams.DOF_Time;
if (IsDefined(level.vl_dof_based_on_focus))
player [[level.vl_dof_based_on_focus]](Dist);
else
{
///// attempts to set the DOF to keep the background blurry and the weapon in focus even when weapon distance from camera moves
/// set defaut values based on Hbra3 with f of 2.0 for it's based distance of level.camParams.CAC_DIST default value
Dist2Tgt = Dist;
player = self;
FStopPerUnit = 0.025;
scaler = 0.65;
fStopBase = 0.613159; //2.0; // base default fstop to be scaled a distance of 72?
BaseDistance = 94.9504; //104
result = ((BaseDistance - Dist2Tgt) * FStopPerUnit);
fStop = fStopBase + result + (result * scaler);
if(fStop < 0.125)
{
fStop = 0.125;
}
else if(fStop > 128)
{
fStop = 128;
}
player SetPhysicalDepthOfField( fStop, Dist2Tgt, level.camParams.DOF_Time, level.camParams.DOF_Time * 2 );
}
}
vlobby_handle_mode_change( mode, newmode, camParams )
{
player = self;
if (isDefined( level.vl_handle_mode_change ))
player [[level.vl_handle_mode_change]]( mode, newmode, camParams );
else
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////// if the mode we are leaving was the mode below, check to see if we should change any post fx.
/// mode is the current mode we are in not the mode we are going to be in after this function runs. newmode is
/// is the mode we are transitioning to.
///
if ( mode == "cac" )
{
player SetDefaultPostFX();
}
else if ( mode == "cao" )
{
}
////
////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////// This is for the newmode that we are going to. Checks newmode and then changes post FX depending on what newmode we want to go to.
/// This will ovewrite any settings that get set above if the newmode changes the same post fx here.
///
if (newmode == "cac")
{
player VisionSetNakedForPlayer("mp_vlobby_refraction_cac", 0);
player LightSetForPlayer("mp_vl_create_a_class");
}
else if ( newmode == "cao" )
{
player SetPhysicalDepthOfField( 1.53, 130, level.camParams.DOF_Time, level.camParams.DOF_Time );
}
else if ( newmode == "prelobby" )
{
player SetDefaultPostFX();
}
else if (mode == "prelobby_members")
{ // shouldn't be used right now.
}
else if (mode == "prelobby_loadout")
{ // shouldn't be used right now.
}
else if (mode == "prelobby_loot")
{ // shouldn't be used right now.
}
else if (newmode == "game_lobby")
{
player SetDefaultPostFX();
// player Set_Avatar_DOF();
}
else if (mode == "startmenu")
{ // shouldn't be used right now.
}
else if (mode == "transition")
{ // shouldn't be used right now.
}
////
////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
SetDefaultPostFX()
{
player = self;
player VisionSetNakedForPlayer("mp_vlobby_room", 0);
player LightSetForPlayer("mp_vlobby_room");
}
SetDefaultDOF()
{
///////////////////////////////////////////////
////////////// vl_dof_based_on_focus() should overide DOF for each camera position when looking at lobby avatars/characters
player = self;
player SetPhysicalDepthOfField( 0.613159, 89.8318, level.camParams.DOF_Time, level.camParams.DOF_Time );
}
fixlocalfocus()
{
if (!isdefined( level.vlavatars[level.vl_focus] ) )
{
foreach ( idx, avatar in level.vlavatars )
{
level.vl_focus = idx;
break;
}
}
if ( !isdefined( level.vlavatars[level.vl_local_focus] ) )
level.vl_local_focus = level.vl_focus;
}
vlobby_player()
{
self endon("disconnect");
wait 0.05;
player = self;
player SetClientOmnvar( "ui_vlobby_round_state", 0 );
player SetClientOmnvar( "ui_vlobby_round_timer", 0 );
player grab_players_classes(); // we grab whenever we start the vl, since we may be coming back from a game straight into the original lobby
player_origin = player.origin;
player_angles = player.angles;
target_origin = player_origin - ( 0, 0, 30 );
player setup_camparams();
player vlobby_lighting_setup();
facedir = AnglesToForward( player.angles );
rightdir = AnglesToRight( player.angles );
movedir = facedir;
ground_origin = GetGroundPosition( player_origin, 20, 512, 120 );
xuid = player getxuid();
localPlayMatchReturn = ( xuid == "" );
targetAvatar = undefined;
level.needLocalMemberId = true;
level.vl_focus = 0;
level.vl_local_focus = 0;
player.team = "spectator"; //
// ownerId for the avatar the camera focus's on.
primary_weapon = "iw5_hbra3_mp";
primWeap = "iw5_hbra3";
if(isdefined(player.loadouts["customClasses"][0]["primary"]) && player.loadouts["customClasses"][0]["primary"] != "none")
{
// this should get us the FULL weapon name with attachments so we should spawn with the correct weapon now and not have to change moments after spawn
loadout_weapon = player.loadouts["customClasses"][0]["primary"];
loadout_attachment1 = player.loadouts["customClasses"][0]["primaryAttachment1"];
loadout_attachment2 = player.loadouts["customClasses"][0]["primaryAttachment2"];
loadout_attachment3 = player.loadouts["customClasses"][0]["primaryAttachment3"];
loadout_camo = player.loadouts["customClasses"][0]["primaryCamo"];
loadout_reticule = player.loadouts["customClasses"][0]["primaryReticule"];
if( IsDefined(loadout_camo) )
{
loadout_camo = int(tableLookup( "mp/camoTable.csv", 1, loadout_camo, 0 ));
}
else
{
loadout_camo = undefined;
}
if( IsDefined(loadout_reticule) )
{
loadout_reticule = int(tableLookup( "mp/reticleTable.csv", 1, loadout_reticule, 0 ));
}
else
{
loadout_reticule = undefined;
}
primary_weapon = maps\mp\gametypes\_class::BuildWeaponName( loadout_weapon, loadout_attachment1, loadout_attachment2, loadout_attachment3, loadout_camo, loadout_reticule );
primWeap = player.loadouts["customClasses"][0]["primary"];
}
else if(isdefined(player.primaryWeapon)) // just incase
{
primary_weapon = player.primaryWeapon;
primWeap = player.pers["primaryWeapon"];
}
cao_spawnpoint = getent("cao_spawnpoint", "targetname");
if ( !localPlayMatchReturn )
{
vlprintln( "adding xuid " + xuid + "from vlobby_player" );
ownerId = add_avatar( xuid );
assert( ownerId == 0 );
player spawn_an_avatar( player.avatar_spawnpoint, primary_weapon, player.secondaryWeapon, primWeap, player.loadoutEquipment, player.loadoutOffhand, player.perks, player.sessionCostume, player.name, ownerId, false );
setEntPlayerXuidForEmblem( level.vlavatars[ownerid], xuid );
thread SetVirtualLobbyPresentable();
}
else
{
level.needToPresent = true; // flag that the next spawn we will need to present for local play returning from a match
}
SetDvar( "virtuallobbymembers", level.xuid2ownerId.size );
// for special cao agent
player.cao_agent = player spawn_an_avatar( cao_spawnpoint, primary_weapon, player.secondaryWeapon, primWeap, player.loadoutEquipment, player.loadoutOffhand, player.perks, player.sessionCostume, player.name, 0, true );
setEntPlayerXuidForEmblem( player.cao_agent, xuid );
hide_avatar( player.cao_agent );
player thread monitor_class_select_or_weapon_change( 0 );
if ( !localPlayMatchReturn )
{
targetAvatar = level.vlavatars[level.vl_focus];
targetAvatar.membertimeout = GetTime();
targetAvatar.currentSelectedClass = player.currentSelectedClass;
targetAvatar.player = player;
targetAvatar.sessionCostume = targetAvatar.costume; // ensure we keep the same randomly picked costume if we have one.
virtual_lobby_set_class( 0, "lobby" + (targetAvatar.currentSelectedClass+1), true );
}
thread monitor_debug_addfakemembers( player, level.camParams );
origin = (-70.7675, -691.293, 507.472); //hardcoding the camera start point to a beter location
toavatar = player.avatar_spawnpoint.origin - origin;
angles = (0,87,0); // hardcoding the start camera angles to better angles to better match the normal camera
toavatar = VectorNormalize( toavatar );
camera = spawn( "script_model", origin );
camera.angles = angles;
camera SetModel( "tag_player" );
camera.startorigin = origin;
camera.startangles = angles;
camera.savedorigin = (0,0,0);
camera.cam_percent_away = 0;
camera.HasReachedFinalPos = true;
camera.CamDirectionForward = true;
camera.cut = true;
camera.Gap = false;
camera.finished = true;
camera.goal_location = origin;
self StoreCameraTargets(camera);
sky_dist_from_cam = 400;
player.camera = camera;
camera.player = player;
player.HasTouchedStick = false;
weaponAngles = (0,90,0);
camera.MovingState = "starting";
level.vlCamera = camera;
player SetOrigin(camera.origin);
player PlayerLinkTo( camera, "tag_player" );
player CameraLinkTo( camera, "tag_player" );
level.in_firingrange = false;
player AllowFire( false );
player prep_for_controls( player.spawned_avatar, player.spawned_avatar.spawn_angles );
player prep_for_controls( player.cao_agent, player.cao_agent.spawn_angles );
updateSessionState("spectator");
camParams = level.camParams;
camParams.camera = camera;
init_path_constants( camera );
bg_dist_from_cam = 300;
level.old_vl_focus = level.vl_focus;
sky_dist_from_cam = 1000;
camForward = AnglesToForward( camera.angles );
bg_plane = undefined;
bg_plane_static = undefined;
bg_plane_angles = undefined;
bg_plane_offset = undefined;
level.camParams.framedelay = level.camParams.pre_lobby_framedelay; // everytime we start the lobby for the first time small delay before we find the avatar camera
thread monitor_player_removed();
thread monitor_vl_mode_change();
fly = false;
testpaths = false;
player SetClientDVar( "cg_fovscale", "0.6153" ); // using this to flag first entry into vlobby
player notify("fade_in");
while (1)
{
avatar_after_spawn(); // we check is weapon loaded now before revealing the lobby, if not loaded we need to keep checking.
if ( level.vlavatars.size == 0 )
{
if ( camParams.mode == "game_lobby" || camParams.mode == "prelobby_loot" )
{
hide_avatar( player.cao_agent );
camera.cut = true; // cut to first camera location when lobby loaded
lobby_update_group_new( camera, undefined, camParams, player.avatar_spawnpoint ); // go to lobby_update_group_new istead of prelobby
vlobby_vegnette(1, "ac130_overlay_pip_vignette_vlobby");
}
wait 0.05;
continue;
}
targetAvatar = level.vlavatars[level.vl_focus];
if (testpaths)
{
testpaths = false;
player thread debug_pathing();
}
if ( GetDvarInt("scr_vl_debugfly" ) > 0 )
{
if (!fly)
{
fly = true;
/#
SetDvar( "r_dof_enable", "0" );
#/
SetDvar( "lui_enabled", "0" );
level.debug_fly = undefined;
player AllowFire( true );
}
player debug_fly( camera );
}
else if ( fly )
{
/#
SetDvar( "r_dof_enable", "1" );
#/
SetDvar( "lui_enabled", "1" );
fly = false;
camera.origin = camera.startorigin;
camera.angles = camera.startangles;
player AllowFire( false );
}
if ( !level.in_firingrange )
{
if ( level.vl_focus != level.old_vl_focus )
{
player prep_for_controls( level.vlavatars[level.vl_focus], level.vlavatars[level.vl_focus].angles); // this was missing angles and would pass in undefined angles before
// no longer need to set anything for old focus because the camera cut works to player avatar looks clean now.
if(camParams.mode != "game_lobby") // do we need this block of code to set the mode at all?
{
camParams.newmode = "transition";
}
level.old_vl_focus = level.vl_focus;
camParams.transitioning = true;
}
if ( isdefined(level.vl_cao_focus) || isdefined(level.prv_vl_cao_focus) )
{
if (!isdefined( level.vl_cao_focus ))
{
camParams.newmode = camParams.pushmode;
level.prv_vl_cao_focus = undefined;
}
else if (!isdefined( level.prv_vl_cao_focus ))
{
camParams.newmode = "cao";
camParams.pushmode = camParams.mode;
level.prv_vl_cao_focus = level.vl_cao_focus;
}
else if (level.vl_cao_focus != level.prv_vl_cao_focus)
{ // switched which part we're looking at
level.prv_vl_cao_focus = level.vl_cao_focus;
}
}
if ( isdefined( level.cac ) || isDefined( level.prv_cac ) )
{
if (!isdefined( level.cac ) )
{
camParams.newmode = camParams.pushmode;
level.prv_cac = undefined;
level.prv_cac_weapon = "none";
}
else if ( !isdefined( level.prv_cac ) )
{
// hide_avatars(); // This makes the avatars pop coming back from CAC get rid of it From Evan
camParams.newmode = "cac";
camParams.pushmode = camParams.mode;
level.prv_cac = level.cac;
}
}
if ( level.vlavatars.size == 0 )
continue;
fixlocalfocus();
targetAvatar = level.vlavatars[level.vl_focus];
if (camParams.newmode != camParams.mode)
{
player vlobby_handle_mode_change( camParams.mode, camParams.newmode, camParams );
if (camParams.newmode == "cac")
{
hide_avatar( player.cao_agent );
player.HasTouchedStick = false;
camParams.mode = camParams.newmode;
camParams.tgt_camoffset_ratio = camParams.CAC_CAMOFFSET_ANGLE_RATIO;
//camParams.cac_weapon_select = false;
// camera.cut = true; no reason to cut to CAC nothing in 3d space to cut to.
targetAvatar = level.vlavatars[level.vl_focus];
player prep_for_controls(targetAvatar, targetAvatar.angles); // save stick and avatar angles when going into CAC
}
else if (camParams.mode == "cac") // if mode was CAC and now new mode is not, so we know that we are leaving CAC
{ // cut if we exit cac as well
//camParams.cac_weapon_select = false;
show_non_owner_avatars();
targetAvatar = level.vlavatars[level.vl_focus];
// camera.cut = true; // we will now only cut from CAC to lobby if focus not the player avatar
player.HasTouchedStick = false;
}
if (camParams.newmode == "cao")
{
if ( IsDefined(level.vl_local_focus) && IsDefined( level.vlavatars[level.vl_local_focus] ) )
{
agent = level.vlavatars[level.vl_local_focus];
level.players[0].costume = agent.costume;
costumeFound = level.players[0] maps\mp\gametypes\_teams::playerCostume();
assert( costumeFound );
costumeFound = agent maps\mp\gametypes\_teams::playerCostume();
assert( costumeFound );
// ensure CaO agent is in synch for whenever we go back to CaO
caoAgent = level.players[0].cao_agent;
vl_avatar_costume( caoAgent, agent.costume );
costumeFound = caoAgent maps\mp\gametypes\_teams::playerCostume();
assert( costumeFound );
// ensure the emblems for the correct player are associated with this actor
// need the xuid for the focus
foreach ( xuid, idx in level.xuid2ownerId )
{
if ( idx == level.vl_local_focus )
{
if ( isDefined( level.cao_xuid ) && level.cao_xuid != xuid )
SetEntPlayerXuidForEmblem( caoAgent, level.cao_xuid, true ); // clear previous cao association
SetEntPlayerXuidForEmblem( caoAgent, xuid );
level.cao_xuid = xuid;
break;
}
}
}
show_avatar( player.cao_agent );
player.cao_agent HackAgentAngles(player.cao_agent.spawn_angles);
hide_avatars();
targetAvatar = player.cao_agent;
player prep_for_controls(player.cao_agent, player.cao_agent.angles);
start_cao_anims();
camParams.mode = camParams.newmode;
camera.cut = true;
player SetOrigin(targetAvatar.origin);
}
else if ( camParams.newmode == "clanprofile" )
{
hide_avatar( player.cao_agent );
show_non_owner_avatars();
targetAvatar = level.vlavatars[level.vl_focus];
start_lobby_anims();
player prep_for_controls(targetAvatar, targetAvatar.angles);
}
/* // we are not using prelobby anymore
else if (camParams.newmode == "prelobby")
{
}
*/
else if (camParams.newmode == "prelobby_loot")
{
camera.cut = true;
}
else if (camParams.newmode == "transition")
{
// if its "transition" just go to game_lobby
// if(camParams.mode == "prelobby")
// {
camParams.newmode = "game_lobby";
// }
}
if (camParams.newmode == "game_lobby")
{
fixlocalfocus(); // was needed when prelobby happned first
// hide_avatar( player.cao_agent ); // was needed when prelobby happened first
vl_focus = 0;
foreach ( idx, avatar in level.vlavatars )
{
vl_focus = idx;
break;
}
// From Evan
if(camParams.mode == "cao" || camParams.mode == "cac" )
{
camera.finished = true;
if ( IsDefined( level.vl_cao_focus ) )
{
level.vl_local_focus = vl_focus;
vl_focus = GetFocusFromController( level.vl_cao_focus );
}
else
{
level.vl_local_focus = vl_focus;
}
}
// sometimes it goes directly to your avatar like from CAO or CAC but we don't want to see the old focus spin for a moment
// could be artifact from going to pre_lobby for a frame after CAC though...
if(isdefined(level.vlavatars) && isdefined(level.old_vl_focus) && isdefined(level.vlavatars[level.old_vl_focus]))
{
player prep_for_controls(level.vlavatars[level.old_vl_focus], level.vlavatars[level.old_vl_focus].angles);
}
// From Evan End
camParams.goal = "waiting";
if(camParams.mode != "cac" ) // using show here can break avatar weapon show/hide state when we are just coming out of CAC
{
show_avatars();
}
level.vl_focus = vl_focus;
level.old_vl_focus = vl_focus;
targetAvatar = level.vlavatars[vl_focus];
if(camParams.mode != "cac")
{
camera.cut = true; // always cut if we were not in CAC
}
// this lets us know if we were someplace else in the lobby instead of our avatar even if old focus got overwritten and
// this lets us avoid cutting the camera movement if we are already on player focus. If player is already focus camera cut when the weapon anim plays can look bad
else if((camParams.mode =="cac") && isdefined(camera.avatar_spawnpoint) && (camera.avatar_spawnpoint != targetAvatar.avatar_spawnpoint))
{
camera.cut = true;
}
start_lobby_anims();
camera.last_avatar_position = targetAvatar.avatar_spawnpoint;
camera.avatar_spawnpoint = targetAvatar.avatar_spawnpoint;
player prep_for_controls(targetAvatar, targetAvatar.angles);
camera.MovingState = "starting";
player SetOrigin(targetAvatar.origin);
}
camParams.mode = camParams.newmode;
}
if (camParams.mode == "startmenu")
{ // shouldn't be used right now.
start_menu_update( camera, camParams );
}
else if ( camParams.mode == "cao" )
{
targetAvatar = player.cao_agent;
cao_update( camera, targetAvatar, camParams );
vlobby_vegnette(1, "ac130_overlay_pip_vignette_vlobby_cao");
}
else if ( camParams.mode == "clanprofile" )
{
clan_profile_update( camera, targetAvatar, camParams );
}
else if ( camParams.mode == "cac" )
{
lobby_update_group_new( camera, level.vlavatars[level.vl_focus], camParams, player.avatar_spawnpoint ); // go ahead and update the camera while in the background of CAC. This way sometimes it will settle before player gets back from CAC
}
// removed legacy prelobby stuff that was here
else if ( camParams.mode == "transition" )
{
/// do transition
camParams.newmode = "game_lobby";
}
else
{ // must be in game lobby
if(camParams.CAOtoLobbyFrameTimer <= 0)
{
hide_avatar( player.cao_agent );
lobby_update_group_new( camera, targetAvatar, camParams, player.avatar_spawnpoint ); // was missing argument.
vlobby_vegnette(1, "ac130_overlay_pip_vignette_vlobby");
}
else
{
camParams.CAOtoLobbyFrameTimer = camParams.CAOtoLobbyFrameTimer - 1;
}
}
}
if ( level.in_firingrange )
{
vlobby_vegnette(0, "ac130_overlay_pip_vignette_vlobby");
}
wait 0.05;
}
}
TableLookupWeaponOffsets(WeaponString,SearchColumn,ReturnColumn)
{
offset = Float(TableLookup( "mp/vlobby_cac_offsets.csv", SearchColumn, WeaponString, ReturnColumn ));
if(!isdefined(offset))
{
offset = 0;
}
return offset;
}
// deleted legacy drift stuff
StoreCameraTargets(camera)
{
PlayerPositions = GetEntArray("player_pos","targetname");
camera.CamerHelperArray = [];
foreach(AvatarSpawn in PlayerPositions)
{
// filling with garbage data for now
camera.CamerHelperArray[camera.CamerHelperArray.size] = AvatarSpawn;
}
foreach(AvatarSpawn in PlayerPositions)
{
// CameraTarget = GetEnt(AvatarSpawn.targetname,"target"); // reverse find entity. find who is targgeting me instead of who I target
CameraTarget = GetEnt(AvatarSpawn.target,"targetname");
if(CameraTarget.script_noteworthy == "camera_target")
{
AvatarSpawn.camera_lookat = CameraTarget;
}
CameraEnt = GetEnt(CameraTarget.target,"targetname");
if(CameraEnt.script_noteworthy == "camera")
{
AvatarSpawn.camera_helper = CameraEnt;
CameraEnt.camera_goal = AvatarSpawn;
CameraEnt.camera_lookat = AvatarSpawn.camera_lookat;
}
if(AvatarSpawn.script_noteworthy == "0")
{
level.camParams.last_camera_helper = AvatarSpawn.camera_helper;
}
Num = int(AvatarSpawn.script_noteworthy);
{
camera.CamerHelperArray[Num] = AvatarSpawn;
}
}
}
// Given the desired camera position and target position, and ratio,
// calculate the vector that will point the camera so the target appears at the correct location on screen
/*
* if ratio is xonscreen/distcamtoscreen, and d is the distance to a point in the center of the screen that
* puts our target where we want in X on screen, and t is the distance to the right of our center point to the target,
* then T/D = ratio and T = D*ratio. If V is our desired normalized vector the camera will point at and R is a normalized
* right vector from our lookat point, C is the camera position and T is the target position, then C + d*V + t*R = T.
* C + d*V + ratio*d*R = T
* d*V + ratio*d*R = T - C
* if we ensure our dZ is 0 for now, then we get V = (vx, vy, 0), R = ( vy, -vx, 0 )
* ( d*vx + ratio*d*vy, d*vy - ratio*d*vx, 0) = T - C = O = (ox, oy, 0)
* Since we will normalize at the end of all of this, we can ignore the d
* And, using linear algebra we can solve
*/
calc_target_dir( camerapos, targetpos, camParams )
{
c2t = targetpos - camerapos;
dist2D = Length2D( c2t );
D = dist2D / sqrt( 1 + camParams.cur_camoffset_ratio*camParams.cur_camoffset_ratio );
vx = c2t[0] - camParams.cur_camoffset_ratio*c2t[1];
vy = camParams.cur_camoffset_ratio*c2t[0] + c2t[1];
v = D * VectorNormalize( (vx, vy, 0) );
// we could test by adding ratio*( v[1], -v[0], 0 ) and we should get c2t[0..1]
// now put the Z back
v = v + ( 0, 0, c2t[2] );
return v;
}
hacky_get_delta_xrot( camParams, rotX )
{
dRot = rotX - camParams.oldRotX;
if (dRot < -180 )
dRot = 360 + dRot;
else if (dRot > 180)
dRot = 360 - dRot;
camParams.oldRotX = rotX;
return dRot;
}
hacky_get_delta_yrot( camParams, rotY )
{
dRot = roty - camParams.oldRotY;
if (dRot < -180 )
dRot = -1;
else if (dRot > 180)
dRot = 1;
else
dRot = 0;
camParams.oldRotY = rotY;
return dRot;
}
CamMove( target, time, acctime, dectime )
{
if (isdefined( self.cut ))
{
//self DontInterpolate();
self.origin = target;
}
else
self moveto( target, time, acctime, dectime );
}
CamRotate( target, time, acctime, dectime )
{
if (isdefined( self.cut ))
self.angles = target;
else
self rotateto( target, time, acctime, dectime );
}
RotateAvatarTagCamera(avatar, spawnpoint)
{
if ( !IsDefined( avatar ) )
{
// removed pointless code here that was just being overwritten anyway.
CameraData = SpawnStruct();
CameraData.camera_tag_origin = ( -70.8, -691.3, 502.2 );
CameraData.camera_tag_angles = ( 0, 87, 0 );
return cameraData;
}
tag_camera_loc_vec3 = avatar GetTagOrigin("TAG_STOWED_BACK");
tag_camera_angles_vec3 = avatar GetTagAngles("TAG_STOWED_BACK");
diff_angles_y = avatar.spawn_angles[1] - avatar.angles[1];
up = (0,0,1); // up is always vertical
NewPos = tag_camera_loc_vec3 - avatar.origin;
RotatedPos = RotatePointAroundVector(up, NewPos, diff_angles_y);
NewCamPos = avatar.origin + RotatedPos;
avatar.camera_tag_origin = NewCamPos;
avatar.camera_tag_angles = (tag_camera_angles_vec3[0], AngleClamp(tag_camera_angles_vec3[1] + diff_angles_y), tag_camera_angles_vec3[2]);
CameraData = SpawnStruct();
CameraData.camera_tag_origin = avatar.camera_tag_origin;
CameraData.camera_tag_angles = avatar.camera_tag_angles;
return CameraData;
}
CheckCamPosition(camera, position, units)
{
if(!IsDefined(units))
{
units = 2;
}
CamDist2Target = distance (position, camera.origin);
if(CamDist2Target >= units)
{
return true;
}
else
{
return false;
}
}
//// Game Lobby with group setup
lobby_update_group_new( camera, targetAvatar, camParams, spawnpoint )
{
if ( !IsDefined( targetAvatar ) ) // moved prelobby stuff here to handle before avatar spawns
{
// hardcoding startingpoint if no avatar
level.camParams.framedelay = level.camParams.pre_lobby_framedelay;
CameraAngles = camera.startangles;
if(IsDefined(spawnpoint))
{
CameraAngles = (0, spawnpoint.angles[1] + 180, 0);
}
newCamOrigin = camera.startorigin;
movedist = Distance( camera.origin, newCamOrigin );
movetime = movedist / camParams.PRELOBBY_MOVESPEED;
if (movetime < 0.1)
{
movetime = 0.1;
}
camera CamMove( newCamOrigin, movetime, movetime*0.5, movetime*0.5 );
camera CamRotate( CameraAngles, movetime, movetime*0.5, movetime*0.5 );
}
else // after avatar has spawned use below for camera
{
// we know the avatar just spawned. We want to save the stick angles and avatar angles once
if(level.camParams.framedelay == level.camParams.pre_lobby_framedelay)
{
self prep_for_controls(targetAvatar, targetAvatar.angles);
}
// hardcoding camera angles to be based on avatar spawnpoint + 180. Not titlted view then. less camera movement.
CameraAngles = (0,87,0);
if(IsDefined(targetAvatar.avatar_spawnpoint))
{
CameraAngles = (0,targetAvatar.avatar_spawnpoint.angles[1] + 180, 0);
}
tag_camera_loc_vec3 = targetAvatar GetTagOrigin("TAG_STOWED_BACK");
// GetAnimData() used to get camera_state. camera_state decides Z and distance values. We take that and then use avatar spawnpoint angles forward * distance to determine XY.
if(!IsDefined(targetAvatar.camera_state))
{
targetAvatar.camera_state = "stand";
}
if(targetAvatar.camera_state == "crouch")
{
CamLocationFloor = targetAvatar.avatar_spawnpoint.origin + (AnglesToForward(targetAvatar.avatar_spawnpoint.angles) * camParams.GAMELOBBYGROUP_CAMERA_CrouchDistance);
CamLocation = (CamLocationFloor[0], CamLocationFloor[1], camParams.GAMELOBBYGROUP_CAMERA_CrouchZ);
}
else if(targetAvatar.camera_state == "hunch")
{
CamLocationFloor = targetAvatar.avatar_spawnpoint.origin + (AnglesToForward(targetAvatar.avatar_spawnpoint.angles) * camParams.GAMELOBBYGROUP_CAMERA_HunchDistance);
CamLocation = (CamLocationFloor[0], CamLocationFloor[1], camParams.GAMELOBBYGROUP_CAMERA_HunchZ);
}
else if(targetAvatar.camera_state == "stand")
{
CamLocationFloor = targetAvatar.avatar_spawnpoint.origin + (AnglesToForward(targetAvatar.avatar_spawnpoint.angles) * camParams.GAMELOBBYGROUP_CAMERA_NormalDistance);
CamLocation = (CamLocationFloor[0], CamLocationFloor[1], camParams.GAMELOBBYGROUP_CAMERA_NormalZ);
}
else if(targetAvatar.camera_state == "zoom_high")
{
CamLocationFloor = targetAvatar.avatar_spawnpoint.origin + (AnglesToForward(targetAvatar.avatar_spawnpoint.angles) * camParams.GAMELOBBYGROUP_CAMERA_CloseDistance);
CamLocation = (CamLocationFloor[0], CamLocationFloor[1], camParams.GAMELOBBYGROUP_CAMERA_UpCloseZ);
}
else
{
CamLocationFloor = targetAvatar.avatar_spawnpoint.origin + (AnglesToForward(targetAvatar.avatar_spawnpoint.angles) * camParams.GAMELOBBYGROUP_CAMERA_NormalDistance);
CamLocation = (CamLocationFloor[0], CamLocationFloor[1], camParams.GAMELOBBYGROUP_CAMERA_NormalZ);
}
camera.goal_location = CamLocation;
// don't update camera until the delay is done.
bCamSHouldUpdate = false;
if(level.camParams.framedelay == 0)
{
bCamSHouldUpdate = CheckCamPosition(camera,CamLocation, 1.5);
}
camParams.cur_camoffset_ratio = camParams.GAMELOBBYGROUP_CAMOFFSET_ANGLE_RATIO;
camParams.tgt_camoffset_ratio = camParams.GAMELOBBYGROUP_CAMOFFSET_ANGLE_RATIO;
camera update_camera_params_ratio( camParams );
AccelTime = 0;
DecelTime = 0;
// movetime = 0.5;
movedist = Distance( camera.origin, CamLocation );
movetime = movedist / camParams.GAMELOBBY_MOVESPEED;
if (movetime < 0.1)
movetime = 0.1;
CorrectedMoveTime = movedist / (camParams.GAMELOBBY_MOVESPEED * level.camParams.GAMELOBBYGROUP_MOVESPEED_MODIFIER);
if (CorrectedMoveTime < 0.1)
CorrectedMoveTime = 0.1;
rotationtime = 1;
mode = GetDvarInt( "virtualLobbyMode", 0 );
if ( mode != LUI_MODE_CAC && mode != LUI_MODE_OBSCURED && mode != LUI_MODE_CAO)
{
self RightStickRotateAvatar(targetAvatar, 0.5);
}
else if(mode == LUI_MODE_OBSCURED || mode == LUI_MODE_CAO)
{
self prep_for_controls(targetAvatar, targetAvatar.angles); // handle this at mode switch in vlobby()
camera.cut = true; // cut if coming out of obscured menu.
}
else if(mode == LUI_MODE_CAC)
{
self prep_for_controls(targetAvatar, targetAvatar.angles);
}
if(level.camParams.framedelay > 0)
{
level.camParams.framedelay = level.camParams.framedelay - 1;
}
///////////////// FIND OUT HERE IF TARGET AVATAR CHANGE OR ANIM CHANGE
if(IsDefined(targetAvatar.avatar_spawnpoint) && IsDefined(camera.avatar_spawnpoint) && targetAvatar.avatar_spawnpoint != camera.avatar_spawnpoint)
{
camera.LastAvatarPositionEnt = camera.avatar_spawnpoint;
camera.avatar_spawnpoint = targetAvatar.avatar_spawnpoint;
camParams.goal = "finding_new_position";
bCamSHouldUpdate = true;
camera.finished = false;
}
else if(bCamSHouldUpdate == true)
{
camParams.goal = "moving";
}
//////////////////////////////////////////////////////////////////////////////////
if(camParams.goal == "waiting")
{
if(bCamSHouldUpdate == true)
{
camParams.goal = "moving";
camera.finished = true;
}
camera.last_avatar_position = targetAvatar.avatar_spawnpoint;
}
///////////////// HERE WE FIND OUR NEW GOAL AVATAR POSITION UP OR DOWN THE AVATAR POSITION INDEX THEN GO TO NEXT CONNECTED NODE
if(camParams.goal == "finding_new_position")
{
if(bCamSHouldUpdate == true)
{
camera.LastAvatarPositionEnt = camera.avatar_spawnpoint;
camera.avatar_spawnpoint = targetAvatar.avatar_spawnpoint;
camera.obstacles = [];
radius = OBSTACLE_RADIUS;
foreach ( avatar in level.vlavatars )
{
obstacle = [];
obstacle["center"] = avatar.avatar_spawnpoint.origin;
obstacle["radius"] = radius;
camera.obstacles[ camera.obstacles.size ] = obstacle;
}
build_path_info( camera, camParams, camera.origin, CamLocation, CameraAngles ); // using new values
camera.fparams = calc_f_from_avatar( targetAvatar );
camera.target_from_avatar = get_target_from_avatar( targetAvatar );
camParams.goal = "moving";
}
camParams.goal = "moving";
}
///////////////// HERE IS WHERE WE ACTUALLY MOVE
if(camParams.goal == "moving")
{
if(level.camParams.framedelay <= 0)
{
level.camParams.framedelay = 0;
if(camera.finished == false)
{
if ( isdefined( camera.cut ) )
{
// hardcoding camera angles
camera CamMove( CamLocation, movetime, AccelTime, DecelTime );
camera CamRotate( CameraAngles, rotationtime, rotationtime * 0.5, rotationtime * 0.5 ); // using new values
camera.finished = true;
}
else
{
camera.finished = update_camera_on_path( camera, camParams );
}
}
if (camera.finished)
{
camera CamMove( CamLocation, CorrectedMoveTime, CorrectedMoveTime * 0.5, CorrectedMoveTime * 0.5 );
camera CamRotate( CameraAngles, CorrectedMoveTime, CorrectedMoveTime * 0.5, CorrectedMoveTime * 0.5 ); // using new values
camParams.goal = "waiting";
}
}
}
level.players[0] Set_Avatar_DOF();
}
if ( isdefined(camera.cut) )
{
camera DontInterpolate();
camera.cut = undefined;
}
if ( GetDVarInt( "virtualLobbyReady", 0 ) == 0 )
{
wait 1.0; // for some reason the transition is not smooth without delaying a bit the set virtualLobbyReady to 1
SetDVar( "virtualLobbyReady", "1" ); // using this to flag first entry into vlobby
thread SetVirtualLobbyPresentable();
}
}
SetVirtualLobbyPresentable()
{
level notify("cancel_vlp");
level endon("cancel_vlp");
// we want to know if the weapon has been loaded first
if ((level.vlavatars.size > 0) && IsDefined(level.vlavatars[0]) && IsDefined(level.vlavatars[0].primaryweapon) && IsWeaponLoaded(level.vlavatars[0].primaryweapon))
{
level.needToPresent = undefined;
wait 0.5;
SetDVar( "virtualLobbyPresentable", "1" ); // using this to flag that we can fade out the coverage
}
else
{
level.needToPresent = true;
}
}
ResetVirtualLobbyPresentable()
{
level notify("cancel_vlp");
level endon("cancel_vlp");
level.needToPresent = undefined;
wait 0.25; // wait same time we wait to remove the last avatar
SetDVar( "virtualLobbyPresentable", "0" ); // using this to flag that we can fade out the coverage
}
MovePlayerEyeToCam(camera)
{
//because we need player eye at cam to build screen space with function WorldPointToScreenPos()
player = level.players[0];
eyePos = player GetEye();
eyeDif = eyePos - player.origin;
player SetOrigin(camera.origin - eyeDif, false); // don't teleport or it won't work with WorldPointToScreenPos()
player SetPlayerAngles((player.angles[0],camera.angles[1],player.angles[2]));
}
GetAspectRatio()
{
AspectRatioData = SpawnStruct();
Resolution = GetDvar( "r_mode", "1280x720 [16:9]" );
Width_X_Height = StrTok(Resolution, " ");
ResolutionArray = StrTok(Width_X_Height[0], "x");
AspectRatioData.Width = stringToFloat(ResolutionArray[0]);
AspectRatioData.Height = stringToFloat(ResolutionArray[1]); // to int not float?
AspectRatioData.AspectRatio = roundDecimalPlaces(AspectRatioData.Width / AspectRatioData.Height, 3);
return AspectRatioData;
}
GetModifiedRotationAngle(targetAvatar, rightStickDiffY, ratio)
{
if((abs(rightStickDiffY - targetAvatar.rotation_total) > 100))
{
if(rightStickDiffY >= 270)
{
targetAvatar.addtobaseangle = targetAvatar.addtobaseangle + (-360 * ratio);
if(targetAvatar.addtobaseangle == -360)
{
targetAvatar.addtobaseangle = 0;
}
}
if(rightStickDiffY <= 100)
{
targetAvatar.addtobaseangle = targetAvatar.addtobaseangle + (360 * ratio);
if(targetAvatar.addtobaseangle == 360)
{
targetAvatar.addtobaseangle = 0;
}
}
}
targetAvatar.rotation_total = rightStickDiffY;
AddtoAngle = ((rightStickDiffY * ratio) + targetAvatar.addtobaseangle);
return AddtoAngle;
}
cao_update( camera, targetAvatar, camParams )
{
/*
cao_params =
[
// [ tag, dist, camZoff ],
[ "j_spineupper", 100, 0 ], // gender
[ "j_spineupper", 50, 4 ], // shirt
[ "J_head", 30, 0 ], // head
[ "j_knee_ri", 45, 8 ], // pants
[ "j_head", 25, 0 ], // eyewear
[ "j_head", 25, 4 ], // hat
[ "j_spineupper", 50, -4 ], // gear
[ "j_knee_ri", 30, 0 ], // kneepads
[ "j_wrist_le", 40, 4 ], // gloves
[ "j_ankle_ri", 40, 12 ], // shoes
[ "j_spineupper", 100, 0 ] // exo
];
params = cao_params[ level.prv_vl_cao_focus ];
tag = params[0];
dist = params[1];
camzoff = params[2];
target = targetAvatar GetTagOrigin( tag );
targetzoff = target[2] - targetAvatar.origin[2];
cameraZOff = camzoff;
/* // if we want a custom animation for selected part
if(isdefined(tag) && tag == "j_wrist_le")
{
if(!IsDefined(targetAvatar.cao_anim))
{
targetAvatar.cao_anim = false;
}
if(targetAvatar.cao_anim == false)
{
targetAvatar SetAnimState( "lobby_idle", 4 );
targetAvatar.cao_anim = true;
}
}
*/
self RightStickRotateAvatar(targetAvatar, 0.5);
/*
dRotX = hacky_get_delta_xrot( camParams, rightStick[0] );
camParams.zoom += dRotX/360;
if (camParams.zoom < 0)
camParams.zoom = 0;
else if (camParams.zoom > 1)
camParams.zoom = 1;
*/
camParams.CAOtoLobbyFrameTimer = camParams.CAOtoLobbyFrameDelay; // set the delay to wait before camera snaps to lobby after CAO menu fade
start_origin = targetAvatar.origin + (0, 0, -20) + (AnglesToForward(targetAvatar.spawn_angles) * 120);
camParams.zoom = camParams.CAO_CAMERA_RATIO;
// from prelobby
camParams.dist = camParams.CAO_NEARDIST + (camParams.CAO_FARDIST - camParams.CAO_NEARDIST)*camParams.zoom;
cameraZOff = camParams.CAO_CAMERAZOFF + camParams.CAO_CAMERAZOFF_ZOOM*camParams.zoom;
targetzoff = camParams.CAO_TARGETZOFF + camParams.CAO_TARGETZOFF_ZOOM*(1 - camParams.zoom);
camParams.tgt_camoffset_ratio = camParams.CAO_CAMOFFSET_RATIO + camParams.PRELOBBY_RATIO_ZOOM*(camParams.zoom - 1);
// level.camParams.camoffset_ratio_maxspeed
camera update_camera_params_ratio( camParams );
ch_cyl_zoff = camParams.CH_CYL_ZOFF_NEAR + ( camParams.CH_CYL_ZOFF_FAR - camParams.CH_CYL_ZOFF_NEAR )*camParams.zoom;
// we will transition to the required position
target_origin = targetAvatar.origin + (0,0,targetzoff);
// c2t = target_origin - camera.startorigin; // always use startorigin as our reference, in case we've come back from orbit mode
c2t = target_origin - (start_origin + camParams.origin_offset); // always use startorigin as our reference, in case we've come back from orbit mode
c2t = camParams.dist*VectorNormalize( c2t );
c2t = (c2t[0], c2t[1], -1*cameraZOff );
c2t = camParams.dist*VectorNormalize( c2t );
newCamOrigin = target_origin - c2t;
if ( IsDefined( level.caoAvatarPosOffset ) )
{
target_origin = target_origin + level.caoAvatarPosOffset;
newCamOrigin = newCamOrigin + level.caoAvatarPosOffset;
}
// keep camParams.angle up to date so we'll lerp from it if we transition
t2c = -1*c2t;
t2cangles = VectorToAngles( t2c );
camParams.angle = t2cangles[1] - targetAvatar.startangles[1]; // since we will reset to these when we transition
movedist = Distance( camera.origin, newCamOrigin );
movetime = movedist / camParams.PRELOBBY_MOVESPEED;
if (movetime < 0.1)
movetime = 0.1;
camera CamMove( newCamOrigin, movetime, movetime*0.5, movetime*0.5 );
// we want the camera pointing at the avatar
v = calc_target_dir( newCamOrigin, target_origin, camParams );
angles = VectorToAngles( v );
camera CamRotate( angles, movetime, movetime*0.5, movetime*0.5 );
if ( isdefined(camera.cut) )
{
camera DontInterpolate();
camera.cut = undefined;
}
}
start_menu_update( camera, camParams )
{
}
clan_profile_update( camera, targetAvatar, camParams )
{
// Once designed, set up the camera & movemement controls for switching
// between clan highlights
}
monitor_vl_mode_change()
{
self endon("disconnect");
while (true)
{
mode = GetDvarInt( "virtualLobbyMode", 0 );
if ( level.camParams.mode != "cao" )
{
if ( ( level.camParams.mode != "prelobby" ) && ( mode == LUI_MODE_PRELOBBY ) )
{
level.camParams.newmode = "game_lobby"; // go to game_lobby instead of prelobby
}
if ( ( string_find( level.camParams.mode, "prelobby" ) >= 0 ) && ( mode == LUI_MODE_LOBBY ) )
{
level.camParams.newmode = "game_lobby"; // go to game_lobby instead of prelobby
}
}
wait 0.05;
}
}
FindPositionNum()
{
position_number = self.script_noteworthy;
position_number = int(position_number);
return position_number;
}
monitor_player_removed()
{
self waittill("disconnect");
self.camera Delete();
vlprint( "remove all ownerIds due to disconnect\n");
foreach ( xuid, ownerId in level.xuid2ownerId )
{
remove_avatar( ownerId );
}
}
// set agent values like agent mesh, health, owner, and team
set_agent_values( team, sessionteam )
{
// set the agent to the player's team, need a wayway to modify agent name because now it is exactly the same as the owner and it is confusing
self set_agent_team( team );
self.agent_gameParticipant = false;
self.isActive = true;
self.spawnTime = GetTime();
self.IsSniper = false; // based on owner's class
self.sessionteam = sessionteam;;
}
// copied from _bots_strategy.gsc so we don't need to include it
bot_disable_tactical_goals()
{
self.disable_tactical_goals = true;
self.tactical_goals = [];
}
wait_load_costume_show( agent )
{
if ( IsAlive( agent ) )
{
isLevelCAC = isdefined( level.cac );
isPracticeNonOwner = GetDvarInt( "practiceroundgame" ) && agent.ownerid != 0;
if ( !isLevelCAC && !isPracticeNonOwner )
{
show_avatar( agent );
}
}
}
wait_load_costume_timeout( seconds, agent )
{
self endon( "disconnect" );
agent endon( "wait_load_costume" );
// self endon( "wait_load_costume" );
agent endon( "death" );
wait( seconds );
wait_load_costume_show( agent );
agent notify( "wait_load_costume" );
}
wait_load_costume( agent )
{
self endon( "disconnect" );
// self notify( "wait_load_costume" ); // do we need this noified on player? in what case would notify on agent fail?
// self endon( "wait_load_costume" );
agent notify( "wait_load_costume" );
agent endon( "wait_load_costume" );
agent endon( "death" );
hide_avatar( agent );
self thread wait_load_costume_timeout( 5.0, agent );
allLoaded = self LoadCostumeModels( agent.costume, agent.team );
while ( !allLoaded )
{
wait( 0.1 );
allLoaded = self LoadCostumeModels( agent.costume, agent.team );
}
wait_load_costume_show( agent );
agent notify( "wait_load_costume" );
}
#using_animtree( "multiplayer_vlobby" );
spawn_an_avatar( spawnpoint, primaryWeapon, secondaryWeapon, primWeap, equipment, offhand, perks, costume, memberName, ownerid, is_CAO_agent )
{
team = "spectator";
sessionTeam = "none";
agent = alloc_avatar();
spawnpoint.spawned_avatar = agent;
agent.avatar_spawnpoint = spawnpoint;
agent.costume = costume;
agent.activeCostume = 0;
// agent.rotation_offset = 15; // for old horse shoe lobby
agent.rotation_offset = 0;
agent set_agent_values( team, sessionTeam );
//agent SetSpawnWeapon( primaryWeapon );
ground_origin = GetGroundPosition( agent.avatar_spawnpoint.origin, 20, 512, 120 );
agent.spawn_angles = (spawnpoint.angles[0], spawnpoint.angles[1] + agent.rotation_offset, spawnpoint.angles[2]); // offset because camera is offset, want facing camera or at least tune it
agent.angles = agent.spawn_angles;
agent Show();
agent.ownerid = ownerid;
//agent.agentname = memberName; // TODO: agentname is now a localized string, so we can't use this field to store the player name
agent SetPlayerAngles(agent.spawn_angles);
agent SetOrigin( ground_origin, true );
agent.angles = agent.spawn_angles;
agent.startangles = agent.spawn_angles;
agent.storedangleY = agent.angles[1];
agent.mouseRot = 0;
agent.storedRightStickY = 0;
agent.rotation_total = 0;
agent.addtobaseangle = 0;
agent.rotation_parent = spawn("script_origin", agent.origin);
// agent LinkToSynchronizedParent(agent.rotation_parent);
// agent.framedelay = 10;
agent.camera_cut = true;
agent.camera_tag_origin = (0,0,0);
agent.camera_tag_angles = (0,0,0);
agent MotionBlurHQEnable();
if(!isdefined(self.spawned_avatar))
{
self.spawned_avatar = agent;
}
// if the the player has just joined the lobby keep the camera stable so it doesn't spin.
agent EnableAnimState( true );
if(!isdefined(is_CAO_agent))
{
is_CAO_agent = false;
}
if(is_CAO_agent == false)
{
level.vlavatars[ownerid] = agent;
animdata = agent GetAnimData(primWeap);
agent use_animstate( animdata.alias, true, animdata.animstate );
agent thread CheckWeapChange(primaryWeapon); // we want check for attachments so we need full name
}
else
{
agent.is_CAO_agent = true;
primaryWeapon = undefined;
agent.primaryWeapon = undefined;
primWeap = undefined;
// animdata = agent GetAnimData(primWeap);
// agent use_animstate( animdata.alias, true, animdata.animstate );
// agent thread CheckWeapChange(primWeap);
// agent SetAnimClass( "vlobby_animclass" );
agent use_animstate( "cao_01", true, "lobby_idle" );
}
agent maps\mp\gametypes\_spawnlogic::addToCharactersArray();
if(IsALive(agent))
{
vl_avatar_loadout( undefined, ownerid, primaryWeapon, secondaryWeapon, primWeap, equipment, offhand, perks, costume, agent );
if ( level.players.size > 0 )
{
level.players[0] thread wait_load_costume( agent );
}
}
if (isdefined( level.cac ))
{
// hide_avatar( agent ); // hide any new agents while we are in cac
}
// Hide all non-owner avatars in practice round
if ( GetDvarInt( "practiceroundgame" ) && ownerid != 0 )
hide_avatar( agent );
else
show_avatar( agent );
return agent;
}
CheckWeapChange(primaryWeapon)
{
self endon( "disconnect" ); // self is the agent here, this disconnect should probably actually be on the player
self endon( "death" );
self endon( "free_avatar" );
if( !IsDefined( self.primaryWeapon ) )
{
self.primaryWeapon = primaryWeapon;
}
self.stored_weapon = self.primaryWeapon;
WeaponString = undefined;
while(true)
{
if ( !IsDefined( self.primaryWeaponEnt ) || !IsDefined( self.akimboWeaponEnt ) )
{
wait 0.05;
continue;
}
if(IsDefined(self) && IsDefined(self.primaryWeapon) && IsALive(self) )
{
WeapStringArray = StrTok(self.primaryWeapon, "_");
WeaponString = WeapStringArray[0] + "_" + WeapStringArray[1];
}
// From Evan
CurrentAnim = self GetAnimEntry();
CaoAnim = self GetAnimEntry( "lobby_idle", "cao_01" );
animdata = self GetAnimData(WeaponString);
DesiredAnim = self GetAnimEntry(animdata.animstate, animdata.alias);
if(isdefined(level.camParams.mode))
{
/#
/// so animators can test animations easier in the lobby
if ( GetDvarInt( "scr_vl_anim_choose_anim_enable", 0 ) )
{
if(self == level.vlavatars[level.vl_focus])
{
///// debug for selecting own animation;
animdata = self GetAnimData(WeaponString);
anim_index = GetDvarInt( "scr_vl_anim_index", 0 );
AnimCount = self GetAnimEntryCount(animdata.animstate);
if(anim_index >= 0 && anim_index <= (AnimCount - 1))
{
DesiredAnim = self GetAnimEntry(animdata.animstate, anim_index);
// alias = self GetAnimEntryAlias(animdata.animstate, anim_index);
if(CurrentAnim != DesiredAnim)
{
// level.camParams.framedelay = 6;
self.stored_weapon = self.primaryweapon; // store the full weapon name
self use_animstate( anim_index, undefined, animdata.animstate );
}
}
}
// so we don't run the normal code below
wait(0.05);
continue;
}
#/
if(level.camParams.newmode != "cao" && level.camParams.mode != "cao")
{
if(IsDefined(self) && IsDefined(WeaponString) && IsALive(self) )
{
weaponLoaded = IsWeaponLoaded( self.primaryWeapon );
changedWeapon = self.stored_weapon != self.primaryweapon;
needUpdate = changedWeapon || (CurrentAnim != DesiredAnim);
DiffBaseWeapon = GetWeaponBaseName(self.stored_weapon) != GetWeaponBaseName(self.primaryweapon); // find out if it is same base weapon just with diff attachments
if( needUpdate )
{
if ( weaponLoaded )
{
if(DiffBaseWeapon) // checking to see if it is a diff base weapon, if not we don't want to hide, just update attachments
{
hide_avatar_primary_weapon( self ); // hide weapons once the new one has loaded so it doesn't look crazy in transition
hide_avatar_akimbo_weapon( self );
thread AttachWeaponDelayed(self); // if we attach same frame as we hide you see weapon like shield turn 90 degrees in 1 frame
thread ShowPrimaryDelayed(self); // show the weapon shortly after transition starts
}
self.primaryWeaponEnt SetPickupWeapon( self.primaryWeapon );
self.akimboWeaponEnt SetPickupWeapon( self.primaryWeapon ); // might as well set the akimbo mesh here even if we don't show it just incase we do need to show it it should be the correct mesh
if( IsSubStr( self.primaryWeapon, "akimbo" ) || IsSubStr( self.primaryWeapon, "akimboxmg"))
{
if(DiffBaseWeapon)
{
thread ShowAkimboDelayed(self);
}
}
else
{
self.akimboWeaponEnt hide();
self.akimboWeaponEnt HideAllParts();
}
self.stored_weapon = self.primaryweapon; // when its actually loaded thats when we store this now
animdata = self GetAnimData(WeaponString);
self.camera_state = animdata.camera_state;
// self use_animstate(animdata.alias, undefined, animdata.animstate );
self thread AnimDelayed(animdata.alias, animdata.animstate ); // delay anim so that that hiding and AttachWeaponDelayed() can run
}
else
{
// From Evan - I don't think we need this. If GetAnimData() fails to find the anim it returns CAO anim in the data.
// Sometimes when the weapon is not loaded it plays CAO anim for a moment and then swaps to the correct anim,
/// it looks janky and weird.
// self use_animstate( "cao_01", undefined, "lobby_idle" );
}
}
}
}
}
wait(0.5);
}
}
// has this weapon been loaded? bool
IsWeaponLoaded(weapon)
{
weaponLoaded = false;
if ( level.players.size > 0 )
{
weaponLoaded = level.players[0] WorldWeaponsLoaded( weapon );
if ( !weaponLoaded )
{
level.players[0] LoadWeapons( weapon );
}
}
return weaponLoaded;
}
// delay attaching weapon to bone
AttachWeaponDelayed(agent)
{
wait(level.camParams.CACWeaponAttachDelayTime);
AttachPrimaryWeapon(agent);
}
// so that weapons have time to hide before anim kicks off and makes them look weird. (knife / shield)
AnimDelayed(alias, animstate )
{
wait(level.camParams.CACWeaponAnimDelayTime);
self use_animstate(alias, undefined, animstate );
}
#using_animtree( "multiplayer_vlobby" );
GetAnimData(primWeap)
{
animdata = SpawnStruct();
animdata.alias = primWeap;
if(IsDefined(primWeap) && primWeap != "" && primWeap != "none")
{
animdata.animstate = TableLookup( "mp/vlobby_cac_offsets.csv", 0, primWeap, 5 );
animdata.camera_state = TableLookup( "mp/vlobby_cac_offsets.csv", 0, primWeap, 6 );
}
if(!IsDefined(animdata.animstate) || animdata.animstate == "")
{
animdata.animstate = "lobby_idle";
animdata.alias = "cao_01";
animdata.camera_state = "stand";
}
self SetAnimClass( "vlobby_animclass" );
if(!IsDefined(animdata.camera_state))
{
animdata.camera_state = "stand";
}
if(!IsDefined(self.camera_state))
{
self.camera_state = animdata.camera_state;
}
return animdata;
}
vl_give_weapons( player, agent )
{
//Set misc models for arm launcher and/or abilities.
AddLaunchers(agent);
if (!isdefined( agent.primaryWeapon ) )
return; // weapons haven't been setup yet, so don't try to give them
if (!isdefined(agent.animAlias))
{
assertMsg( "VL Agent doesn't have an animstate" );
}
else
{ // get the models and link them
if (agent.primaryWeapon != "none")
{
if (!isdefined(agent.primaryWeaponEnt))
{
primaryWeaponEnt = spawn( "weapon_" + agent.primaryWeapon, (0,0,0) );
xuid = get_xuid_for_avatar( agent );
setEntPlayerXuidForEmblem( primaryWeaponEnt, xuid );
agent.primaryWeaponEnt = primaryWeaponEnt;
primaryWeaponEnt.primaryweapon = agent.primaryWeapon;
agent.primaryWeaponEnt show(); // when it first spawns in show it.
agent.primaryWeaponEnt ShowAllParts();
agent.primaryWeaponEnt SetPickupWeapon( agent.primaryWeapon );
AttachPrimaryWeapon(agent);
}
else if (agent.primaryWeaponEnt.primaryWeapon != agent.primaryWeapon)
{
// agent.primaryWeaponEnt SetPickupWeapon( agent.primaryWeapon ); // handle in CheckWeapChange(primaryWeapon)
agent.primaryWeaponEnt.primaryweapon = agent.primaryWeapon;
}
// don't atutomatically show attach changed weapons here. Handle it in CheckWeapChange(primaryWeapon)
/////////////////////////////////////// Akimbo weapons /////////////////////////////////
//////
if (!isdefined(agent.akimboWeaponEnt))
{
akimboWeaponEnt = spawn( "weapon_" + agent.primaryWeapon, (0,0,0) );
xuid = get_xuid_for_avatar( agent );
setEntPlayerXuidForEmblem( akimboWeaponEnt, xuid );
agent.akimboWeaponEnt = akimboWeaponEnt;
akimboWeaponEnt.primaryweapon = agent.primaryWeapon;
}
else if (agent.akimboWeaponEnt.primaryWeapon != agent.primaryWeapon)
{
// agent.akimboWeaponEnt SetPickupWeapon( agent.primaryWeapon ); // handle in CheckWeapChange(primaryWeapon)
agent.akimboWeaponEnt.primaryweapon = agent.primaryWeapon;
}
tag_left = "tag_weapon_left";
if( IsSubStr( agent.akimboWeaponEnt.primaryWeapon, "combatknife" ) )
tag_left = "tag_inhand";
if ( IsSubStr( agent.akimboWeaponEnt.primaryWeapon, "riotshield" ) )
tag_left = "tag_weapon_left";
agent.akimboWeaponEnt unlink();
agent.akimboWeaponEnt.origin = agent GetTagOrigin(tag_left);
agent.akimboWeaponEnt.angles = agent GetTagAngles(tag_left);
agent.akimboWeaponEnt LinkToSynchronizedParent( agent, tag_left );
agent.akimboWeaponEnt SetOwnerOriginal( player );
if( IsSubStr( agent.primaryWeaponEnt.primaryWeapon, "akimbo" ) || IsSubStr( agent.primaryWeaponEnt.primaryWeapon, "akimboxmg" ))
{
thread ShowAkimboDelayed(agent);
}
else if(!isdefined(agent.stored_weapon)) // if avatar is new and not akimbo weapon then hide them
{
agent.akimboWeaponEnt hide();
agent.akimboWeaponEnt HideAllParts();
}
//////
////////////////////////////////////////////////////////////////////
}
if ( agent.secondaryWeapon != "none" )
{
if ( IsSubStr( agent.secondaryWeapon, "combatknife" ) )
{
if ( IsDefined( agent.secondaryWeaponEnt ) )
{
if ( agent.secondaryWeaponEnt IsLinked() )
{
agent.secondaryWeaponEnt Unlink();
}
agent.secondaryWeaponEnt Delete();
}
}
else
{
if (!isdefined(agent.secondaryWeaponEnt))
{
secondaryWeaponEnt = spawn( "weapon_" + agent.secondaryWeapon, (0,0,0) );
xuid = get_xuid_for_avatar( agent );
setEntPlayerXuidForEmblem( secondaryWeaponEnt, xuid );
agent.secondaryWeaponEnt = secondaryWeaponEnt;
secondaryWeaponEnt.secondaryweapon = agent.secondaryWeapon;
}
else if (agent.secondaryWeaponEnt.secondaryWeapon != agent.secondaryWeapon)
{
agent.secondaryWeaponEnt SetPickupWeapon( agent.secondaryWeapon );
agent.secondaryWeaponEnt.secondaryweapon = agent.secondaryWeapon;
}
// TODO: support stowedOffsetModel from weapondef
tag = "tag_stowed_back";
agent.secondaryWeaponEnt unlink();
agent.secondaryWeaponEnt.origin = agent GetTagOrigin(tag);
agent.secondaryWeaponEnt.angles = agent GetTagAngles(tag);
agent.secondaryWeaponEnt LinkToSynchronizedParent( agent, tag );
agent.secondaryWeaponEnt ShowAllParts();
agent.secondaryWeaponEnt SetOwnerOriginal( player );
}
}
}
}
// AttachPrimaryWeapon. Moved this block of code so it can be used anywhere.
AttachPrimaryWeapon(agent)
{
player = undefined;
if(isdefined(agent.player))
{
player = agent.player;
}
tag = "tag_weapon_right";
if( IsSubStr( agent.primaryWeaponEnt.primaryWeapon, "combatknife" ) )
tag = "tag_inhand";
if ( IsSubStr( agent.primaryWeaponEnt.primaryWeapon, "riotshield" ) )
tag = "tag_weapon_left";
agent.primaryWeaponEnt unlink();
agent.primaryWeaponEnt.origin = agent GetTagOrigin(tag);
agent.primaryWeaponEnt.angles = agent GetTagAngles(tag);
// TODO: support tag_weapon_left decision
agent.primaryWeaponEnt LinkToSynchronizedParent( agent, tag );
agent.primaryWeaponEnt SetOwnerOriginal( player );
}
AddLaunchers(agent)
{
//Set misc models for arm launcher and/or abilities.
agent Detach("npc_exo_arm_launcher_R", "J_Elbow_RI", false);
agent Detach("npc_exo_arm_launcher_L", "J_Elbow_LE", false);
//handling wildcards
if( isdefined( agent.lethal ) && agent.lethal != "specialty_null" )
{
//check for dual tacticals
if( !agent _hasPerk( "specialty_wildcard_dualtacticals" ) )
{
//if no dual tacticals attach the launcher
// are these creating a new ent everytime this function is called? Should we be spawning a script_model once instead and just hide/show?
agent attach( "npc_exo_arm_launcher_R", "J_Elbow_RI", true );
}
else
{
//show ability here.
}
}
if( isdefined( agent.tactical ) && agent.tactical != "specialty_null" )
{
//check for dual lethals
if ( agent _hasPerk( "specialty_wildcard_duallethals" ) )
{
//if dual lethals attach the left arm launch
agent attach( "npc_exo_arm_launcher_L", "J_Elbow_LE", true );
}
else
{
//show ability here.
}
}
}
ShowAkimboDelayed(agent)
{
agent endon("death");
agent.primaryWeaponEnt endon("death");
agent endon( "hide_akimbo_weapon" );
wait(level.camParams.CACWeaponDelayTime);
if(level.camParams.newmode != "cao" && level.camParams.mode != "cao")
{
if( IsSubStr( agent.primaryWeaponEnt.primaryWeapon, "akimbo" ) || IsSubStr( agent.primaryWeaponEnt.primaryWeapon, "akimboxmg"))
{
agent.akimboWeaponEnt show();
agent.akimboWeaponEnt ShowAllParts();
}
}
}
ShowPrimaryDelayed(agent)
{
agent endon("death");
agent.primaryWeaponEnt endon("death");
agent endon( "hide_primary_weapon" );
wait(level.camParams.CACWeaponDelayTime);
isPracticeNonOwner = GetDvarInt( "practiceroundgame" ) && agent.ownerid != 0;
if(level.camParams.newmode != "cao" && level.camParams.mode != "cao" && !isPracticeNonOwner)
{
agent.primaryWeaponEnt show();
agent.primaryWeaponEnt ShowAllParts();
}
}
vl_avatar_costume( agent, costume, setcostume )
{
agent TakeAllWeapons();
agent DetachAll();
agent.headModel = undefined;
if ( isDefined( costume ) )
agent.costume = costume;
if ( !IsDefined( agent.costume ) || !maps\mp\gametypes\_teams::validCostume( agent.costume ) )
{
if ( isdefined( agent.sessionCostume ) && maps\mp\gametypes\_teams::validCostume( agent.sessionCostume ) )
agent.costume = agent.sessionCostume;
else
{
agent.costume = maps\mp\gametypes\_teams::getDefaultCostume();
agent.sessionCostume = agent.costume;
}
}
if (IsDefined(setcostume) && setcostume )
{
level.players[0].costume = agent.costume;
costumeFound = level.players[0] maps\mp\gametypes\_teams::playerCostume();
assert( costumeFound );
costumeFound = agent maps\mp\gametypes\_teams::playerCostume();
assert( costumeFound );
// ensure CaO agent is in synch for whenever we go back to CaO
caoAgent = level.players[0].cao_agent;
vl_avatar_costume( caoAgent, agent.costume );
costumeFound = caoAgent maps\mp\gametypes\_teams::playerCostume();
assert( costumeFound );
}
}
vl_avatar_loadout( player, ownerid, primaryWeapon, secondaryWeapon, primWeap, equipment, offhand, perks, costume, agent )
{
if(!isdefined(agent))
{
agent = level.vlavatars[ownerid];
}
canLocalUpdate = false;
if ( IsDefined( agent.loadout ) && ( agent.loadout.player_controller >= 0 ) )
canLocalUpdate = true;
vl_avatar_costume( agent, costume );
/#
if ( getdvarint("scr_vl_printcostume",0) )
{
print( "ownerid " + ownerid + "\n" );
for ( i=0; i<level.costumeCategories.size; i++ )
{
print( " " + level.costumeCategories[i] + ": " + agent.costume[i] + "\n" );
}
}
#/
agent maps\mp\gametypes\_teams::playerModelForWeapon( primWeap, getBaseWeaponName( secondaryWeapon ) );
if ( canLocalUpdate && IsDefined( level.players[0] ) )
{
level.players[0] SetCostumeModels( agent.costume );
}
agent.primaryWeapon = primaryWeapon;
// agent.secondaryWeapon = secondaryWeapon;
agent.secondaryWeapon = "none"; // secondary weapons clip into the character models so disabling.
agent.tactical = offhand;
agent.lethal = equipment;
agent.perks = perks;
vl_give_weapons( player, agent );
}
monitor_class_select_or_weapon_change( ownerid )
{
self endon("disconnect");
while (true)
{
self waittill( "luinotifyserver", channel, index );
if ( (channel == "classpreview" || channel == "classpreview_postcopy") && IsDefined(index) )
{
if ( index >= 0 )
{
controller = index & 15;
classIndex = int(index / 16);
vlprint( "classpreview " + channel + " controller=" + controller + " class=" + classIndex );
if ( classIndex > 0)
{
level.cac = true; // ensure the cac view (weapon view) is active.
self.currentSelectedClass = classIndex-1;
}
ownerid = GetFocusFromController( controller );
// If this loadout selection change resulted from a 'copy class/loadout' event,
// delay the avatar refresh until the next update cycle, otherwise the avatar
// displayed will be showing the destination slot's loadout before copying.
delayedRefresh = ( channel == "classpreview_postcopy" );
avatar = level.vlavatars[ownerid];
if (IsDefined( avatar ) )
{
level.vl_focus = ownerid;
level.vl_local_focus = ownerid;
virtual_lobby_set_class( ownerid, "lobby" + (self.currentSelectedClass+1), !delayedRefresh );
level.cac_weapon = avatar.primaryWeapon;
}
level.forceAvatarRefresh = delayedRefresh;
}
else
{
// exiting CaC
level.cac = undefined;
}
}
}
}
monitor_cac_set_weapon( ownerid, newWeaponName )
{
ignore = "";
/#
if ( newWeaponName != "none" )
ignore = tablelookup( "mp/statstable.csv", 4, newWeaponName, 51 ); // for dev
#/
if ( ( newWeaponName != "current" ) && ( newWeaponName != "none" ) && ( ignore == "" ) )
{
requiredAttachment = tablelookup( "mp/statstable.csv", 4, newWeaponName, 40 );
if ( requiredAttachment == "" )
requiredAttachment = "none";
weaponName = maps\mp\gametypes\_class::buildWeaponName( newWeaponName,requiredAttachment, "none", "none" ); // w/o attachments here (only required attachments)
}
else if ( newWeaponName == "none" )
{
weaponName = "none";
}
else
{
avatar = level.vlavatars[ownerid];
weaponName = avatar.primaryWeapon;
}
level.cac_weapon = weaponName;
}
has_suffix( search_string, suffix )
{
if ( search_string.size >= suffix.size )
{
if ( GetSubStr( search_string, search_string.size - suffix.size, search_string.size ) == suffix )
{
return true;
}
}
return false;
}
monitor_create_a_class( ownerid )
{
self endon("disconnect");
notifies = []; // we'll ensure we keep any notifies we got while we wait for level.camParams to become valid
while (!isdefined(level.camParams))
{
self waittill( "luinotifyserver", channel, id );
if ( isDefined(id) )
notifies[notifies.size] = [ channel, id ];
else
notifies[notifies.size] = [ channel ];
}
while (true)
{
if ( notifies.size > 0 )
{
note = notifies[0];
newnotifies = [];
for (i=1; i<notifies.size; i++ )
newnotifies[newnotifies.size] = notifies[i];
notifies = newnotifies;
channel = note[0];
if ( note.size > 1 )
id = note[1];
else
id = undefined;
}
else
self waittill( "luinotifyserver", channel, id );
if ( channel == "cac" && IsDefined(id) )
{
if (id == 0)
{ // closing cac menu
level.cac = undefined;
}
else
{ // opening cac menu
level.cac = true;
}
level.vl_cao_focus = undefined;
}
else if ( (channel == "weapon_highlighted") && IsDefined(id) )
{
if ( IsSubStr( id, "stream:" ) )
{
tokens = StrTok( id, ":" );
if ( tokens.size > 1 )
{
weaponName = tokens[tokens.size - 1];
if ( !has_suffix( weaponName, "_mp" ) )
{
weaponName += "_mp";
}
vlprintln( "weapon_stream: " + weaponName );
weaponsArray = [weaponName]; // now weapon is stored in an array and seems to work better
self LoadWeapons( weaponsArray );
}
monitor_cac_set_weapon( ownerid, "none" );
}
else
{
vlprintln( "weapon_highlighted "+ id );
monitor_cac_set_weapon( ownerid, id );
}
}
else if ( (channel == "lootscreen_weapon_highlighted") && IsDefined(id) )
{
// 'lootscreen_weapon_highlighted' basically combines 'cac' with 'weapon_highlighted' since
// we need to send them together frequently on the loot screen
if ( id == "none" )
{
level.cac = undefined;
}
else if ( id == "reset" )
{
// trying to get offset working in CAC weapon select screen and loot screen but not CAC screen
// when you hit A button on loot screen this happens.
level.cac = true;
}
else
{
// when loot screen starts
//monitor_cac_set_weapon( ownerid, id );
level.cac = true;
}
// keep cached camera mode to 'prelobby_loot' when browsing on the loot screen,
// we don't want to store 'cac'/'cao' cam modes since we're temporarily switching
// among them
//level.camParams.pushmode = "prelobby_loot";
// make sure cao mode is off, could be on when moving focus from gear loot to weapon loot
// Keep this level.vl_cao_focus = undefined;
level.vl_cao_focus = undefined;
}
else
{
previewAttach = 0;
if ( channel == "preview_attach1" )
previewAttach = 1;
else if ( channel == "preview_attach2" )
previewAttach = 2;
else if ( channel == "preview_attach3" )
previewAttach = 3;
if ( (previewAttach > 0) && IsDefined(id) )
{
avatar = level.vlavatars[ownerid];
entry = avatar.loadout;
primary = TableLookup( "mp/statstable.csv", 0, entry.primary, 4 );
primaryAttachment1 = TableLookup( "mp/attachmenttable.csv", 0, entry.primaryattachment1, 3 );
primaryAttachment2 = TableLookup( "mp/attachmenttable.csv", 0, entry.primaryattachment2, 3 );
primaryAttachment3 = TableLookup( "mp/attachmenttable.csv", 0, entry.primaryattachment3, 3 );
primaryCamo = entry.primaryCamo;
if ( id != "current" )
{
if ( previewAttach == 1)
{
primaryAttachment1 = id;
}
else if ( previewAttach == 2 )
{
primaryAttachment2 = id;
}
else if ( previewAttach == 3 )
{
primaryAttachment3 = id;
}
}
level.cac_weapon = maps\mp\gametypes\_class::BuildWeaponName( primary, primaryAttachment1, primaryAttachment2, primaryAttachment3, primaryCamo, undefined/* primaryReticle*/ );
}
}
}
}
GetFocusFromController( controller )
{
foreach ( idx, avatar in level.vlavatars )
{
if ( IsDefined( avatar.loadout ) && IsDefined( avatar.loadout.player_controller ) && ( avatar.loadout.player_controller == controller ) )
return idx;
}
vlprintln( "unable to find avatar for controller " + controller );
return -1; // default to 0 when we can't find the focus.
}
virtual_lobby_set_class( ownerid, class, refreshAvatar, force, agent )
{
if( (isDefined( self.pers["class"] ) && self.pers["class"] == class) && ( !IsDefined(force) || !force ) )
return;
self.pers["class"] = class;
self.class = class;
self maps\mp\gametypes\_class::setClass( self.pers["class"] );
self.tag_stowed_back = undefined;
self.tag_stowed_hip = undefined;
self maps\mp\gametypes\_class::giveAndApplyLoadout( self.pers["team"], self.pers["class"] );
if ( refreshAvatar )
{
vl_avatar_loadout( self, ownerid, self.primaryWeapon, self.secondaryWeapon, self.pers["primaryWeapon"], self.loadoutEquipment, self.loadoutOffhand, self.perks, self.costume );
if(isdefined(self.cao_agent))
{
vl_avatar_loadout( self, ownerid, undefined, self.secondaryWeapon, self.pers["primaryWeapon"], self.loadoutEquipment, self.loadoutOffhand, self.perks, self.costume, self.cao_agent );
}
}
}
grab_players_classes()
{
customclasses = [ "privateMatchCustomClasses", "customClasses" ];
self.loadouts = [];
self.currentSelectedClass = 0;
foreach (class in customclasses)
{
level.forceCustomClassLoc = class;
self.loadouts[class] = [];
for (class_num=0; class_num<10; class_num++) // note the number may need to come from playerdata
{
loadout = [];
loadout["primary"] = maps\mp\gametypes\_class::cac_getWeapon( class_num, 0 );
loadout["primaryAttachment1"] = maps\mp\gametypes\_class::cac_getWeaponAttachment( class_num, 0 );
loadout["primaryAttachment2"] = maps\mp\gametypes\_class::cac_getWeaponAttachmentTwo( class_num, 0 );
loadout["primaryAttachment3"] = maps\mp\gametypes\_class::cac_getWeaponAttachmentThree( class_num, 0 );
loadout["primaryCamo"] = maps\mp\gametypes\_class::cac_getWeaponCamo( class_num, 0 );
loadout["primaryReticle"] = maps\mp\gametypes\_class::cac_getWeaponReticle( class_num, 0 );
for (i=0; i<6; i++)
{
loadout["perk"+i] = maps\mp\gametypes\_class::cac_getPerk( class_num, i );
}
for (i=0; i<3; i++)
{
loadout["wildcard"+i] = maps\mp\gametypes\_class::cac_getWildcard( class_num, i );
}
loadout["secondary"] = maps\mp\gametypes\_class::cac_getWeapon( class_num, 1 );
loadout["secondaryAttachment1"] = maps\mp\gametypes\_class::cac_getWeaponAttachment( class_num, 1 );
loadout["secondaryAttachment2"] = maps\mp\gametypes\_class::cac_getWeaponAttachmentTwo( class_num, 1 );
loadout["secondaryAttachment3"] = maps\mp\gametypes\_class::cac_getWeaponAttachmentThree( class_num, 1 );
loadout["secondaryCamo"] = maps\mp\gametypes\_class::cac_getWeaponCamo( class_num, 1 );
loadout["secondaryReticle"] = maps\mp\gametypes\_class::cac_getWeaponReticle( class_num, 1 );
loadout["equipment"] = maps\mp\gametypes\_class::cac_getEquipment( class_num, 0 );
loadout["offhand"] = maps\mp\gametypes\_class::cac_getEquipment( class_num, 1 );
self.loadouts[class][class_num] = loadout;
}
}
level.forceCustomClassLoc = undefined;
}
update_local_class( primary, primaryAttachment1, primaryAttachment2, primaryAttachment3, primaryCamo, primaryReticle, secondary, secondaryAttachment1, secondaryAttachment2, secondaryCamo, secondaryReticle, lethal, tactical, wildcard1, wildcard2, wildcard3, perk0, perk1, perk2, perk3, perk4, perk5 )
{
class_num = int(self.currentSelectedClass);
class = cac_getCustomClassLoc();
self.loadouts[class][class_num]["primary"] = primary;
self.loadouts[class][class_num]["primaryAttachment1"] = primaryAttachment1;
self.loadouts[class][class_num]["primaryAttachment2"] = primaryAttachment2;
self.loadouts[class][class_num]["primaryAttachment3"] = primaryAttachment3;
self.loadouts[class][class_num]["primaryCamo"] = primaryCamo;
self.loadouts[class][class_num]["primaryReticle"] = primaryReticle;
self.loadouts[class][class_num]["secondary"] = secondary;
self.loadouts[class][class_num]["secondaryAttachment1"] = secondaryAttachment1;
self.loadouts[class][class_num]["secondaryAttachment2"] = secondaryAttachment2;
self.loadouts[class][class_num]["secondaryCamo"] = secondaryCamo;
self.loadouts[class][class_num]["secondaryReticle"] = secondaryReticle;
self.loadouts[class][class_num]["equipment"] = lethal;
self.loadouts[class][class_num]["lethal"] = lethal;
self.loadouts[class][class_num]["offhand"] = tactical;
self.loadouts[class][class_num]["tactical"] = tactical;
self.loadouts[class][class_num]["wildcard0"] = wildcard1;
self.loadouts[class][class_num]["wildcard1"] = wildcard2;
self.loadouts[class][class_num]["wildcard2"] = wildcard3;
self.loadouts[class][class_num]["perk0"] = perk0;
self.loadouts[class][class_num]["perk1"] = perk1;
self.loadouts[class][class_num]["perk2"] = perk2;
self.loadouts[class][class_num]["perk3"] = perk3;
self.loadouts[class][class_num]["perk4"] = perk4;
self.loadouts[class][class_num]["perk5"] = perk5;
}
loadout_changed( orgLoadout, newLoadout )
{
if (!IsDefined(orgLoadout))
return true;
if ( orgLoadout.primary != newLoadout.primary )
return true;
if ( orgLoadout.primaryattachment1 != newLoadout.primaryattachment1 )
return true;
if ( orgLoadout.primaryattachment2 != newLoadout.primaryattachment2 )
return true;
if ( orgLoadout.primaryattachment3 != newLoadout.primaryattachment3 )
return true;
if ( orgLoadout.primarycamo != newLoadout.primarycamo )
return true;
if ( orgLoadout.secondary != newLoadout.secondary )
return true;
if ( orgLoadout.secondaryattachment1 != newLoadout.secondaryattachment1 )
return true;
if ( orgLoadout.secondaryattachment2 != newLoadout.secondaryattachment2 )
return true;
if ( orgLoadout.secondarycamo != newLoadout.secondarycamo )
return true;
if ( orgLoadout.tactical != newLoadout.tactical )
return true;
if ( orgLoadout.lethal != newLoadout.lethal )
return true;
return false;
}
costume_changed( orgCostume, newCostume )
{
if ( !isdefined( orgCostume ) )
{
if ( !isdefined( newCostume ) )
return false;
return true;
}
if ( orgCostume.size != newCostume.size )
return true;
if ( !maps\mp\gametypes\_teams::validCostume( newCostume ) )
return false; // if the communicated costume is invalid, then flag as no change
for ( i = 0; i < newCostume.size; i++ )
{
if ( newCostume[i] < 0 )
return false; // if any entries in the new costume are invalid, no change
if ( orgCostume[i] != newCostume[i] )
return true;
}
return false;
}
setDefaultCostumeIfNeeded( costume )
{
if ( costume[level.costumeCat2Idx["head"]] == 0 )
costume[level.costumeCat2Idx["head"]] = 1;
if ( !costume[level.costumeCat2Idx["shirt"]] )
costume[level.costumeCat2Idx["shirt"]] = 1;
if ( !costume[level.costumeCat2Idx["pants"]] )
costume[level.costumeCat2Idx["pants"]] = 1;
if ( !costume[level.costumeCat2Idx["gloves"]] )
costume[level.costumeCat2Idx["gloves"]] = 1;
if ( !costume[level.costumeCat2Idx["shoes"]] )
costume[level.costumeCat2Idx["shoes"]] = 1;
if ( !costume[level.costumeCat2Idx["gear"]] )
costume[level.costumeCat2Idx["gear"]] = 1;
if ( !costume[level.costumeCat2Idx["exo"]] )
costume[level.costumeCat2Idx["exo"]] = 1;
return costume;
}
// this is actually where other players that are not THE player get their gear etc and then start the avatar/agent spawn process
monitor_member_class_changes()
{
level.mccqueue = [];
while (true)
{ // it looks like there are situations where level.players is reset to undefined for some period of time
// wait until we've finished the initialization. Ensure we've setup our camera parameters, so the spawn_an_avatar call can properly setup
while ( !isdefined( level.players ) || ( level.players.size == 0 ) || !IsDefined( level.camParams ) )
{
wait 0.05;
}
while ( isdefined( level.players ) && ( level.players.size > 0 ) )
{
// now apply each entry.
foreach (entry in level.mccqueue)
{
primary = TableLookup( "mp/statstable.csv", 0, entry.primary, 4 );
primaryAttachment1 = TableLookup( "mp/attachmenttable.csv", 0, entry.primaryattachment1, 3 );
primaryAttachment2 = TableLookup( "mp/attachmenttable.csv", 0, entry.primaryattachment2, 3 );
primaryAttachment3 = TableLookup( "mp/attachmenttable.csv", 0, entry.primaryattachment3, 3 );
primaryCamo = entry.primaryCamo;
primaryCamoName = TableLookup( "mp/camoTable.csv", 0, entry.primaryCamo, 1 );
primaryReticle = entry.primaryReticle;
primaryReticleName = TableLookup( "mp/reticleTable.csv", 0, entry.primaryReticle, 1 );
secondary = TableLookup( "mp/statstable.csv", 0, entry.secondary, 4 );
secondaryAttachment1 = TableLookup( "mp/attachmenttable.csv", 0, entry.secondaryattachment1, 3 );
secondaryAttachment2 = TableLookup( "mp/attachmenttable.csv", 0, entry.secondaryattachment2, 3 );
secondaryAttachment3 = "none";
secondaryCamo = entry.secondaryCamo;
secondaryCamoName = TableLookup( "mp/camoTable.csv", 0, entry.secondaryCamo, 1 );
secondaryReticle = entry.secondaryReticle;
secondaryReticleName = TableLookup( "mp/reticleTable.csv", 0, entry.secondaryReticle, 1 );
lethal = TableLookup( "mp/perktable.csv", 0, entry.lethal, 1 );
tactical = TableLookup( "mp/perktable.csv", 0, entry.tactical, 1 );
wildcard1 = TableLookup( "mp/perktable.csv", 0, entry.wildcard1, 1 );
wildcard2 = TableLookup( "mp/perktable.csv", 0, entry.wildcard2, 1 );
wildcard3 = TableLookup( "mp/perktable.csv", 0, entry.wildcard3, 1 );
perk1 = TableLookup( "mp/perktable.csv", 0, entry.perk1, 1 );
perk2 = TableLookup( "mp/perktable.csv", 0, entry.perk2, 1 );
perk3 = TableLookup( "mp/perktable.csv", 0, entry.perk3, 1 );
perk4 = TableLookup( "mp/perktable.csv", 0, entry.perk4, 1 );
perk5 = TableLookup( "mp/perktable.csv", 0, entry.perk5, 1 );
perk6 = TableLookup( "mp/perktable.csv", 0, entry.perk6, 1 );
primaryWeapon = maps\mp\gametypes\_class::BuildWeaponName( primary, primaryAttachment1, primaryAttachment2, primaryAttachment3, primaryCamo, primaryReticle );
secondaryWeapon = maps\mp\gametypes\_class::BuildWeaponName( secondary, secondaryAttachment1, secondaryAttachment2, secondaryAttachment3, secondaryCamo, secondaryReticle );
weaponName = getBaseWeaponName( primaryWeapon );
costume = [];
costume[level.costumeCat2Idx["gender"]] = entry.gender;
costume[level.costumeCat2Idx["shirt"]] = entry.shirt;
costume[level.costumeCat2Idx["head"]] = entry.head;
costume[level.costumeCat2Idx["pants"]] = entry.pants;
costume[level.costumeCat2Idx["eyewear"]] = entry.eyewear;
costume[level.costumeCat2Idx["hat"]] = entry.hat;
costume[level.costumeCat2Idx["kneepads"]] = entry.kneepads;
costume[level.costumeCat2Idx["gloves"]] = entry.gloves;
costume[level.costumeCat2Idx["shoes"]] = entry.shoes;
costume[level.costumeCat2Idx["gear"]] = entry.gear;
costume[level.costumeCat2Idx["exo"]] = entry.exo;
perks = [];
if ( isDefined( wildcard1 ) )
perks[wildcard1] = true;
if ( isDefined( wildcard2 ) )
perks[wildcard2] = true;
if ( isDefined( wildcard3 ) )
perks[wildcard3] = true;
if ( !isdefined(level.xuid2ownerId[entry.xuid]) && all_avatars_scheduled_for_delete() )
{ // We want to reuse one scheduled for delete
reuse_avatar( entry.xuid );
}
if (!isdefined(level.xuid2ownerId[entry.xuid]))
{ // need to spawn the avatar
ownerId = add_avatar( entry.xuid );
vlprint( "PartyMemberClassChange "+entry.xuid+" : " +primaryWeapon+","+secondaryWeapon+","+lethal+","+tactical+"\n");
SetDvar( "virtuallobbymembers", level.xuid2ownerId.size );
spawnpoint = maps\mp\gametypes\vlobby::getSpawnPoint( ownerId );
// since we don't know teams, we put them all on the same team...
spawn_an_avatar( spawnpoint, primaryWeapon, secondaryWeapon, weaponName, lethal, tactical, perks, costume, entry.name, ownerId, false );
avatar_after_spawn( ownerId );
setEntPlayerXuidForEmblem( level.vlavatars[ownerId], entry.xuid );
level.vlavatars[ownerId].loadout = entry;
level.vlavatars[ownerId].membertimeout = GetTime() + 4000;
if ( level.vlavatars.size == 1 )
{
// ensure CaO agent is in synch for whenever we go back to CaO
caoAgent = level.players[0].cao_agent;
vl_avatar_costume( caoAgent, level.vlavatars[ownerId].costume );
costumeFound = caoAgent maps\mp\gametypes\_teams::playerCostume();
}
// if (ownerid == 0)
// {
// level.players[0].spawned_avatar.preview_prim_weap_num = entry.primary;
// }
}
else
{ // change the avatar's loadout
ownerId = level.xuid2ownerId[entry.xuid];
avatar = level.vlavatars[ownerId];
if ( entry.player_controller >= 0 ) //(ownerId == 0)
{
if ( level.vl_local_focus == ownerId )
{
//vlprint( "PartyMemberClassChange update_local_class "+entry.xuid+" slot="+level.players[0].currentSelectedClass + " : " +primaryWeapon+","+secondaryWeapon+","+lethal+","+tactical+"\n");
level.players[0] update_local_class( primary, primaryAttachment1, primaryAttachment2, primaryAttachment3, primaryCamoName, primaryReticleName, secondary, secondaryAttachment1, secondaryAttachment2, secondaryCamoName, secondaryReticleName, lethal, tactical, wildcard1, wildcard2, wildcard3, perk1, perk2, perk3, perk4, perk5, perk6 );
}
if ( IsDefined( avatar.previewCostume ) )
{
if ( isdefined( avatar.costumes ) && isdefined( avatar.costumes[ avatar.previewCostume ] ) )
costume = avatar.costumes[ avatar.previewCostume ];
else
{
print( "ownerId " + ownerId + " doesnt have a costume " + avatar.previewCostume );
costume = level.players[0] maps\mp\gametypes\_class::cao_getCostumeByIndex( avatar.previewCostume );
}
costume = setDefaultCostumeIfNeeded( costume );
// if a particular costume is bad, ensure it is fixed.
if ( !isdefined(avatar.costumes) )
avatar.costumes = [];
avatar.costumes[avatar.previewCostume] = costume;
if ( avatar.previewGearCategory != "none" )
{
catIdx = level.costumeCat2Idx[avatar.previewGearCategory];
costume[catIdx] = avatar.previewGearId;
}
}
}
if ( loadout_changed( avatar.loadout, entry ) || costume_changed( avatar.costume, costume ) || ( IsDefined( level.forceAvatarRefresh ) && level.forceAvatarRefresh ) )
{
vlprint( "Updating xuid "+entry.xuid+" with ownerId="+ownerId+"\n");
vlprint( "PartyMemberClassChange "+entry.xuid+" : " +primaryWeapon+","+secondaryWeapon+","+lethal+","+tactical+"\n");
if ( IsDefined( avatar.player ) )
avatar.player.costume = costume; // this may need to wait for a commit
vl_avatar_loadout( avatar.player, ownerid, primaryWeapon, secondaryWeapon, weaponName, lethal, tactical, perks, costume );
if(entry.player_controller >= 0)
{ // update the cao agent
vl_avatar_loadout( avatar.player, ownerid, undefined, secondaryWeapon, weaponName, lethal, tactical, perks, costume, level.players[0].cao_agent );
}
avatar.loadout = entry;
level.forceAvatarRefresh = false;
}
}
}
level.mccqueue = [];
update_avatars();
wait 0.05;
}
}
}
override_member_loadout_for_practice_round( entry )
{
if ( !IsDefined( level.practice_round_costume ) )
{
level.practice_round_max_costumes = TableGetColumnCount( level.practiceRoundCostumeTableName ) - 1;
level.practice_round_costume = RandomInt( level.practice_round_max_costumes );
}
if ( !IsDefined( level.practice_round_class ) )
{
practice_round_max_classes = TableGetColumnCount( level.practiceRoundClassTableName ) - 1;
level.practice_round_class = RandomInt( practice_round_max_classes );
}
/#
SetDevDvarIfUninitialized( "scr_test_pr_classes", 0 );
if ( GetDvarInt( "scr_test_pr_classes", 0 ) )
{
time_per_char = 2000;
time_total = level.practice_round_max_costumes * time_per_char;
level.practice_round_costume = Int( ( GetTime() % time_total ) / time_per_char );
level.practice_round_costume = level.practice_round_costume % level.practice_round_max_costumes;
}
#/
assert( level.practice_round_costume < level.practice_round_max_costumes );
newEntry = entry;
// Get a practice round costume and put it in the entry
newCostume = GetCostumeFromTable( level.practiceRoundCostumeTableName, level.practice_round_costume + 1 );
newEntry.gender = newCostume[ level.costumeCat2Idx["gender"] ];
newEntry.shirt = newCostume[ level.costumeCat2Idx["shirt"] ];
newEntry.head = newCostume[ level.costumeCat2Idx["head"] ];
newEntry.pants = newCostume[ level.costumeCat2Idx["pants"] ];
newEntry.eyewear = newCostume[ level.costumeCat2Idx["eyewear"] ];
newEntry.hat = newCostume[ level.costumeCat2Idx["hat"] ];
newEntry.gear = newCostume[ level.costumeCat2Idx["gear"] ];
newEntry.kneepads = newCostume[ level.costumeCat2Idx["kneepads"] ];
newEntry.gloves = newCostume[ level.costumeCat2Idx["gloves"] ];
newEntry.shoes = newCostume[ level.costumeCat2Idx["shoes"] ];
newEntry.exo = newCostume[ level.costumeCat2Idx["exo"] ];
// Give everyone weapons from the practice round classes
classIndex = level.practice_round_class;
classColumn = classIndex + 1;
// Primary Weapon
primaryWeapon = TableLookup( level.practiceRoundClassTableName, 0, "loadoutPrimary", classColumn );
primaryAttach1 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutPrimaryAttachment", classColumn );
primaryAttach2 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutPrimaryAttachment2", classColumn );
primaryAttach3 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutPrimaryAttachment3", classColumn );
primaryCamo = TableLookup( level.practiceRoundClassTableName, 0, "loadoutPrimaryCamo", classColumn );
primaryReticle = TableLookup( level.practiceRoundClassTableName, 0, "loadoutPrimaryReticle", classColumn );
newEntry.primary = Int( TableLookup( "mp/statstable.csv", 4, primaryWeapon, 0 ) );
newEntry.primaryattachment1 = Int( TableLookup( "mp/attachmenttable.csv", 3, primaryAttach1, 0 ) );
newEntry.primaryattachment2 = Int( TableLookup( "mp/attachmenttable.csv", 3, primaryAttach2, 0 ) );
newEntry.primaryattachment3 = Int( TableLookup( "mp/attachmenttable.csv", 3, primaryAttach3, 0 ) );
newEntry.primarycamo = Int( TableLookup( "mp/camoTable.csv", 1, primaryCamo, 0 ) );
newEntry.primaryreticle = Int( TableLookup( "mp/reticleTable.csv", 1, primaryReticle, 0 ) );
// Secondary Weapon
secondaryWeapon = TableLookup( level.practiceRoundClassTableName, 0, "loadoutSecondary", classColumn );
secondaryAttach1 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutSecondaryAttachment", classColumn );
secondaryAttach2 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutSecondaryAttachment2", classColumn );
secondaryCamo = TableLookup( level.practiceRoundClassTableName, 0, "loadoutSecondaryCamo", classColumn );
secondaryReticle = TableLookup( level.practiceRoundClassTableName, 0, "loadoutSecondaryReticle", classColumn );
newEntry.secondary = Int( TableLookup( "mp/statstable.csv", 4, secondaryWeapon, 0 ) );
newEntry.secondaryattachment1 = Int( TableLookup( "mp/attachmenttable.csv", 3, secondaryAttach1, 0 ) );
newEntry.secondaryattachment2 = Int( TableLookup( "mp/attachmenttable.csv", 3, secondaryAttach2, 0 ) );
newEntry.secondarycamo = Int( TableLookup( "mp/camoTable.csv", 1, secondaryCamo, 0 ) );
newEntry.secondaryreticle = Int( TableLookup( "mp/reticleTable.csv", 1, secondaryReticle, 0 ) );
// Wildcards
wildcard1 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutWildcard1", classColumn );
wildcard2 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutWildcard2", classColumn );
wildcard3 = TableLookup( level.practiceRoundClassTableName, 0, "loadoutWildcard3", classColumn );
newEntry.wildcard1 = Int( TableLookup( "mp/perktable.csv", 1, wildcard1, 0 ) );
newEntry.wildcard2 = Int( TableLookup( "mp/perktable.csv", 1, wildcard2, 0 ) );
newEntry.wildcard3 = Int( TableLookup( "mp/perktable.csv", 1, wildcard3, 0 ) );
return newEntry;
}
add_party_member_class_change( entry )
{
if ( GetDvarInt( "practiceroundgame" ) )
entry = override_member_loadout_for_practice_round( entry );
// There should only be one entry on the queue for any given xuid
for ( i=0; i<level.mccqueue.size; i++)
{
if ( level.mccqueue[i].xuid == entry.xuid )
{
level.mccqueue[i] = entry;
entry = undefined;
break;
}
}
if ( IsDefined( entry ) )
{ // add a new one.
level.mccqueue[level.mccqueue.size] = entry;
}
}
party_members( loadouts )
{
if ( !IsDefined(level.xuid2ownerId) )
return; // ignore these calls until we've spawned the local player
// reset the timeouts for all members that we have avatars for
foreach ( loadout in loadouts )
{
xuid = loadout.xuid;
ownerId = level.xuid2ownerid[xuid];
if ( IsDefined( ownerId ) )
{
avatar = level.vlavatars[ ownerId ];
if ( IsDefined( avatar ) )
{
avatar.membertimeout = GetTime() + 2000;
avatar.memberHasTimedOut = undefined;
}
}
if ( loadout.primary >= 0 )
{
add_party_member_class_change( loadout );
}
}
}
monitor_member_timeouts()
{
while (true)
{
localplay = GetDvarInt( "splitscreen", 0 );
online = IsOnlineGame();
systemlink = IsSystemLink();
foreach (ownerId, avatar in level.vlavatars)
{
if ( avatar_scheduled_for_removal( ownerId ) )
continue;
//if ( ( ownerId == 0 ) && ( online || systemlink ) )
// continue; // Always require avatar 0 in online and systemlink, localplay or mainmenu allows there to be no avatars
if (avatar.membertimeout >= 0)
{
if (avatar.membertimeout < GetTime())
{ // this member hasn't sent us an update, so assume they're not in the party anymore
if ( ownerId == 0 && !IsDefined( avatar.memberHasTimedOut ) )
{ // require two timeouts for ownerId 0
avatar.membertimeout = GetTime() + 2000;
avatar.memberHasTimedOut = 1;
continue;
}
vlprint( "Schedule removal of ownerId "+ownerid + " from timeout\n");
schedule_remove_avatar( ownerid ); // note that this doesn't change the level.vlavatars directly
}
}
}
wait 0.05;
}
}
get_e3_costume( idx )
{
table = "mp/E3CostumeTable.csv";
costume = [];
for (i = 0; i<level.costumeCat2Idx.size; i++)
{
costume[i] = int(TableLookupByRow( table, i+1, idx+1 ));
}
return costume;
}
monitor_debug_addfakemembers( player, camParams )
{
/#
while ( true )
{
if ( IsDefined( level.vl_fakemembers ) && level.vl_fakemembers > 0 && !IsDefined( level.debug_fly ) )
{
if(isdefined(camParams.mode) && camParams.mode == "game_lobby")
{
if ( player AdsButtonPressed() )
{
ownerId = level.vl_focus-1;
if (ownerId < 0)
ownerId = 17;
oId = -1;
while ( ownerId != oId )
{
foreach ( oId in level.xuid2ownerId )
{
if (oId == ownerId)
break;
}
if (oId != ownerId)
{
oId = -1;
ownerId--;
if (ownerId < 0)
ownerId = 17;
}
}
level.vl_focus = ownerId;
while ( player AdsButtonPressed() )
wait 0.05;
}
else if ( player AttackButtonPressed() )
{
ownerId = level.vl_focus+1;
if (ownerId > 17)
ownerId = 0;
oId = -1;
while ( ownerId != oId )
{
foreach ( oId in level.xuid2ownerId )
{
if (oId == ownerId)
break;
}
if (oId != ownerId)
{
oId = -1;
ownerId++;
if (ownerId > 17)
ownerId = 0;
}
}
level.vl_focus = ownerId;
while ( player AttackButtonPressed() )
wait 0.05;
}
}
}
if ( GetDvarInt( "scr_vl_addfakemembers", 0 ) > 0 )
{
xuid = ToString(GetTime());
ownerId = add_avatar( xuid );
if ( !IsDefined( level.fake_ownerids ) )
level.fake_ownerids = [];
level.fake_ownerids[level.fake_ownerids.size] = ownerId;
vlprint( "Adding new fake xuid "+xuid+" with ownerId="+ownerId+"\n");
vlprint( "PartyMemberClassChange "+xuid+" : " +player.primaryWeapon+","+player.secondaryWeapon+","+player.loadoutOffhand+","+player.loadoutEquipment+"\n");
//SetDvar( "virtuallobbymembers", level.xuid2ownerId.size );
spawnpoint = maps\mp\gametypes\vlobby::getSpawnPoint( ownerId );
// since we don't know teams, we put them all on the same team...
team = player.team;
sessionTeam = player.sessionteam;
name = "fakeplayer"+ownerId;
//costume = maps\mp\gametypes\_teams::getDefaultCostume();
costume = get_e3_costume( ownerid );
spawn_an_avatar( spawnpoint, player.primaryWeapon, player.secondaryWeapon, player.pers["primaryWeapon"], player.loadoutEquipment, player.loadoutOffhand, player.perks, costume, name, ownerId, false );
avatar_after_spawn( ownerId );
avatar = level.vlavatars[ownerid];
avatar.loadout = level.vlavatars[0].loadout;
avatar.costume = costume;
avatar.sessionCostume = avatar.costume;
avatar SetCostumeModels(avatar.costume);
avatar.membertimeout = GetTime() + 3600000;
SetEntPlayerXuidForEmblem( avatar, xuid );
level.vl_fakemembers++;
SetDvar( "scr_vl_addfakemembers", toString( GetDvarInt( "scr_vl_addfakemembers", 1 ) - 1 ) );
}
if ( GetDvarInt( "scr_vl_addfakemembers", 0 ) < 0 )
{
foreach ( oId in level.fake_ownerids )
{
level.vlavatars[oId].membertimeout = GetTime() + 1000;
level.vl_fakemembers--;
}
level.fake_ownerids = [];
SetDvar( "scr_vl_addfakemembers", "0" );
level.vl_focus = 0;
}
wait 0.05;
}
#/
}
monitor_member_focus_change()
{
self endon("disconnect");
while (true)
{
self waittill( "luinotifyserver", channel, xuid );
if (channel == "member_select")
{
level.vl_focus = level.xuid2ownerId[xuid];
if (!IsDefined(level.vl_focus))
{
vlprint( "vl_focus undefined, setting to 0\n");
level.vl_focus = 0;
}
vlprint( "selected member " + xuid + " ownerId=" + level.vl_focus + "\n" );
}
if ( channel == "vlpresentable" )
{
vlprint( "in main menu\n" );
thread SetVirtualLobbyPresentable();
}
if (channel == "leave_lobby")
{ // xuid leaves lobby
vlprint( "leave_lobby xuid="+xuid + "\n");
if ( xuid == "0" )
{
foreach ( xuid, ownerId in level.xuid2ownerId )
{
vlprint( "Schedule removal of ownerId "+ownerid + "\n");
schedule_remove_avatar( ownerid, 0.25 ); // wait same time we wait to clear virtualLobbyPresentable
}
}
else
{
ownerId = level.xuid2ownerId[xuid];
if ( IsDefined( ownerId ) )
{
vlprint( "Schedule removal of ownerId "+ownerid + "\n");
schedule_remove_avatar( ownerid, 0.25 ); // wait same time we wait to clear virtualLobbyPresentable
}
}
thread ResetVirtualLobbyPresentable();
}
}
}
monitor_cao_set_cao_focus( controller )
{
if ( controller < 0 ) // closing cao
level.vl_cao_focus = undefined;
else // opening cao
{
level.vl_local_focus = GetFocusFromController( controller );
level.vl_cao_focus = 1;
vlprint( "cao ctrl = " + controller + " focus = " + level.vl_local_focus + "\n" );
}
}
cao_set_costumes_from_lua( val )
{
// controller|activeCostume|costumeIdx,...gearids...|costumeIdx,....#controller2|......
vlprintln( "Cao set costumes from lua:" + val );
cntrGrps = StrTok( val, "#" );
foreach ( cntrGrp in cntrGrps )
{
costdefs = StrTok( cntrGrp, "|" );
if ( costdefs.size > 0 )
{
controller = int( costdefs[0] );
focus = GetFocusFromController( controller );
avatar = level.vlavatars[focus];
if ( IsDefined( avatar ) )
{
avatar.activeCostume = int( costdefs[1] );
for ( i = 2; i < costdefs.size; i++ )
{
tokens = StrTok( costdefs[i], "," );
costume = [];
assert( tokens.size == ( level.costumeCat2Idx.size + 1 ) );
for ( type=1; type < tokens.size; type++ )
costume[costume.size] = int(tokens[type]);
if ( !isdefined( avatar.costumes ) )
avatar.costumes = [];
avatar.costumes[int(tokens[0])] = costume;
}
}
}
}
}
monitor_cao_set_costume_preview( val )
{
basetoks = StrTok( val, ":" );
controller = int(basetoks[0]);
tokens = StrTok( basetoks[1], "," );
ownerid = GetFocusFromController( controller );
level.vl_local_focus = ownerid;
avatar = level.vlavatars[ownerid];
if (isdefined( avatar ))
{
avatar.previewCostume = Int( tokens[0] );
avatar.previewGearCategory = tokens[1];
avatar.previewGearId = Int( tokens[2] );
}
return avatar;
}
monitor_create_an_operator( ownerid )
{
self endon("disconnect");
while (true)
{
self waittill( "luinotifyserver", channel, val );
if (channel == "cao")
{
monitor_cao_set_cao_focus( val );
level.caoAvatarPosOffset = undefined;
if ( IsDefined(level.vl_local_focus) )
avatar = level.vlavatars[level.vl_local_focus];
else
avatar = level.vlavatars[ownerid];
if ( val < 0 && IsDefined(avatar) )
{
avatar.previewGearCategory = undefined;
avatar.previewGearId = undefined;
avatar.previewCostume = undefined;
if ( IsDefined(avatar.costumes) )
vl_avatar_costume( avatar, avatar.costumes[avatar.activeCostume], true );
}
}
else if (channel == "lootscreen_gear_highlighted")
{
// gear loot focused on loot screen
level.cac = undefined;
// instead of waiting for level.cac = undefined to take effect on the
// next 'vlobby_player' update, turn off cac mode immediately in case we've just come
// from a loot weapon focus, in which case the next 'vlobby_player' needs to handle
// turning on cao mode
// vlobby_switch_off_cac( level.weaponAvatar );
monitor_cao_set_cao_focus( val );
if ( IsDefined( level.vl_cao_focus ) )
{
level.caoAvatarPosOffset = ( 56, 0, 5 );
}
else
{
level.caoAvatarPosOffset = undefined;
}
// keep cached camera mode to 'prelobby_loot' when browsing on the loot screen,
// we don't want to store 'cac'/'cao' cam modes since we're temporarily switching
// among them
// TODO Do we need this push mode bellow? I don't see it breaking anything, yet..
level.camParams.pushmode = "prelobby_loot";
}
else if ( channel == "costumes" )
{
cao_set_costumes_from_lua( val );
}
else if ( channel == "costume_preview" )
{
monitor_cao_set_costume_preview( val );
}
else if ( channel == "costume_apply" )
{
avatar = monitor_cao_set_costume_preview( val );
if (IsDefined(avatar))
{
// This is now being done in lua, so we can ensure local clients are updated correctly.
catIdx = level.costumeCat2Idx[avatar.previewGearCategory];
if ( isdefined( avatar.costumes ) && isdefined( avatar.costumes[avatar.previewCostume] ) )
{
avatar.costumes[avatar.previewCostume][catIdx] = avatar.previewGearId;
if ( avatar.previewCostume == avatar.activeCostume )
{
avatar SetCostumeModels( avatar.costumes[avatar.previewCostume] ); // update the displayed
}
}
}
}
}
}
monitor_clans()
{
self endon("disconnect");
level.clanMemberOwnerIDs = [];
while (true)
{
self waittill( "luinotifyserver", channel, val );
if (channel == "clanprofile")
{
vlprint( "Using clan profile VL settings\n" );
if ( val < 0 )
level.vl_clanprofile_focus = undefined;
else
level.vl_clanprofile_focus = val;
level.caoAvatarPosOffset = undefined;
//Functionality has been removed for TU1. For a later TU we'll be spawning the 3 member highlights and setting
//their equipment appropriately
}
}
}
hide_avatar( avatar )
{
avatar Hide();
avatar HideAllParts();
hide_avatar_weapons( avatar );
}
show_avatar( avatar )
{
AddLaunchers(avatar);
avatar Show();
avatar ShowAllParts();
if ( isDefined( avatar.primaryWeaponEnt ) )
{
avatar.primaryWeaponEnt Show();
avatar.primaryWeaponEnt ShowAllParts();
}
if ( isDefined( avatar.secondaryWeaponEnt ) )
{
avatar.secondaryWeaponEnt Show();
avatar.secondaryWeaponEnt ShowAllParts();
}
if ( isDefined( avatar.akimboWeaponEnt ) && isDefined( avatar.akimboWeaponEnt.primaryWeapon ))
{
if( IsSubStr( avatar.akimboWeaponEnt.primaryWeapon, "akimbo" ) || IsSubStr( avatar.akimboWeaponEnt.primaryWeapon, "akimboxmg"))
{
avatar.akimboWeaponEnt show();
avatar.akimboWeaponEnt ShowAllParts();
}
}
// level.forceAvatarRefresh = true;
}
hide_avatar_primary_weapon( avatar )
{
if ( isDefined( avatar.primaryWeaponEnt ) )
{
avatar notify( "hide_primary_weapon" );
avatar.primaryWeaponEnt Hide();
avatar.primaryWeaponEnt HideAllParts();
}
}
hide_avatar_secondary_weapon( avatar )
{
if ( isDefined( avatar.secondaryWeaponEnt ) )
{
avatar notify( "hide_secondary_weapon" );
avatar.secondaryWeaponEnt Hide();
avatar.secondaryWeaponEnt HideAllParts();
}
}
hide_avatar_akimbo_weapon( avatar )
{
if ( isDefined( avatar.akimboWeaponEnt ) )
{
avatar notify( "hide_akimbo_weapon" );
avatar.akimboWeaponEnt Hide();
avatar.akimboWeaponEnt HideAllParts();
}
}
hide_avatar_weapons( avatar )
{
hide_avatar_primary_weapon( avatar );
hide_avatar_secondary_weapon( avatar );
hide_avatar_akimbo_weapon( avatar );
}
hide_avatars()
{
foreach (avatar in level.vlavatars)
hide_avatar( avatar );
}
show_avatars()
{
foreach (avatar in level.vlavatars)
show_avatar( avatar );
}
get_xuid_for_avatar( avatar )
{
foreach (xuid, ownId in level.xuid2ownerId)
{
if (isdefined( level.vlavatars[ownId] ) && level.vlavatars[ownId] == avatar )
return xuid;
}
return "";
}
remove_avatar( ownerId )
{
ownId = -1;
foreach (xuid, ownId in level.xuid2ownerId)
{
if (ownId == ownerId)
break;
}
vlprint( "Removing xuid "+xuid+" for ownerId "+ownerId + "\n");
assert(ownId == ownerId);
setEntPlayerXuidForEmblem( level.vlavatars[ownerid], xuid, true ); // release this xuid
level.xuid2ownerId[xuid] = undefined;
level.avatarInfo[ownerId].timeToDelete = 0;
level.avatarInfo[ownerId].avatar = undefined;
SetDvar( "virtuallobbymembers", level.xuid2ownerId.size );
agent = level.vlavatars[ownerId];
level.vlavatars[ownerId] = undefined;
if ( level.vl_focus == ownerId )
{
if ( level.vlavatars.size > 0 )
{
foreach ( idx, avatar in level.vlavatars )
{
level.vl_focus = idx;
break;
}
}
}
hide_avatar( agent );
agent TakeAllWeapons();
agent DetachAll();
agent.headModel = undefined;
agent HideAllParts();
if(isdefined(agent.avatar_spawnpoint.spawned_avatar))
{
agent.avatar_spawnpoint.spawned_avatar = undefined;
}
if ( isdefined(agent.primaryWeaponEnt) )
{
setEntPlayerXuidForEmblem( agent.primaryWeaponEnt, xuid, true ); // release this xuid
agent.primaryWeaponEnt Delete();
agent.primaryWeaponEnt = undefined;
}
if ( isdefined(agent.secondaryWeaponEnt) )
{
setEntPlayerXuidForEmblem( agent.secondaryWeaponEnt, xuid, true ); // release this xuid
agent.secondaryWeaponEnt Delete();
agent.secondaryWeaponEnt = undefined;
}
if ( isDefined( agent.akimboWeaponEnt ) )
{
setEntPlayerXuidForEmblem( agent.akimboWeaponEnt, xuid, true ); // release this xuid
agent.akimboWeaponEnt delete();
agent.akimboWeaponEnt = undefined;
}
agent.primaryWeapon = undefined;
agent.stored_weapon = undefined;
free_avatar( agent );
if ( level.vl_focus == ownerid )
level.vl_focus = 0; // back to the local player
}
reset_bot_settings_for_a_few_frames()
{
level notify("stop_reset_bot_settings");
level endon("stop_reset_bot_settings");
for (i=0; i<2; i++)
{
// turning off animstate resets some settings
self maps\mp\agents\_agent_common::set_agent_health( 100 );
self BotClearScriptEnemy();
self BotClearScriptGoal();
self bot_disable_tactical_goals();
self BotSetFlag("disable_movement", 1);
self BotSetFlag("disable_rotation", 1);
wait 0.05;
}
}
HackAgentAngles(angles)
{
self SetPlayerAngles(angles);
}
#using_animtree( "multiplayer_vlobby" );
use_animstate( animAlias, duringSetup, animstate )
{
RandomPlaybackRate = RandomFloatRange(0.85, 1.15);
enablechanged = false;
if (!IsDefined(self.animAlias))
{
self SetAnimClass( "vlobby_animclass" );
enablechanged = true;
level notify("stop_reset_bot_settings"); // kill if still active
self HackAgentAngles(self.spawn_angles);
}
// AnimEntry = self GetAnimEntry("lobby_idle_energy", 0);
// count = self GetAnimEntryCount("lobby_idle");
if(!IsDefined(animstate))
{
animstate = "lobby_idle";
animAlias = "assault_pose_06";
}
self.animAlias = animAlias;
self.animstate = animstate;
self SetAnimState( animstate, animAlias, RandomPlaybackRate );
if ( !IsDefined(duringSetup) || !duringSetup )
{
self.animAlias = animAlias;
if (enablechanged)
vl_give_weapons(self);
}
}
#using_animtree( "multiplayer_vlobby" );
start_anim()
{
if (isdefined(level.camParams) && isdefined(level.camParams.mode))
{
switch( level.camParams.mode )
{
case "prelobby":
case "prelobby_loot": // same start anim as "prelobby"
animIdx=0;
if (isdefined(level.vlavatars))
{
foreach( avatar in level.vlavatars )
{ /*
if ( avatar == self )
break;
animIdx++;
if (animIdx >= level.num_lobby_idles)
animIdx = 0;
*/
if(!IsDefined(avatar.animAlias))
{
position_num = avatar.avatar_spawnpoint FindPositionNum();
if(isDefined(self.ownerid) && self.ownerid == 0) // forcing the player to get whatever anim we want / be random
{
animIdx = 8;
}
else if(position_num < level.num_lobby_idles)
{
animIdx = position_num;
}
else
{
animIdx++;
if (animIdx >= level.num_lobby_idles)
animIdx = 0;
}
animstate = "lobby_idle";
self use_animstate( animIdx, undefined, animstate );
}
}
}
/*
if(isDefined(self.ownerid) && self.ownerid == 0) // forcing the player to get whatever anim we want / be random
{
// animIdx = RandomIntRange(0, level.num_lobby_idles - 1);
}
*/
break;
case "transition":
case "game_lobby":
case "cac":
case "clanprofile":
animIdx=0;
if (isdefined(level.vlavatars))
{
foreach( avatar in level.vlavatars )
{
if(!IsDefined(avatar.animAlias))
{
position_num = avatar.avatar_spawnpoint FindPositionNum();
if(isDefined(self.ownerid) && self.ownerid == 0) // forcing the player to get whatever anim we want / be random
{
animIdx = 8;
}
else if(position_num < level.num_lobby_idles)
{
animIdx = position_num;
}
else
{
animIdx++;
if (animIdx >= level.num_lobby_idles)
animIdx = 0;
}
animstate = "lobby_idle";
self use_animstate( animIdx, undefined, animstate );
}
}
}
break;
case "cao":
if(!IsDefined(self.animAlias))
{
if(isDefined(self.ownerid) && self.ownerid == 0) // forcing the player to get whatever anim we want / be random
{
animIdx = 8;
}
else
{
animIdx = RandomIntRange(0, level.num_lobby_idles - 1); /// probably should never happen currently, we want to just use whatever anim was assigned in pr elobby or game lobby for now
}
animstate = "lobby_idle";
self use_animstate( animIdx, undefined, animstate );
}
break;
default: // shouldn't happen, but handle it none the less.
if(!IsDefined(self.animAlias))
{
if(isDefined(self.ownerid) && self.ownerid == 0) // forcing the player to get whatever anim we want / be random
{
animIdx = 8;
}
else
{
animIdx = RandomIntRange(0, level.num_lobby_idles - 1); /// probably should never happen currently, we want to just use whatever anim was assigned in pr elobby or game lobby for now
}
animstate = "lobby_idle";
self use_animstate( animIdx, undefined, animstate );
}
break;
}
}
}
start_prelobby_anims()
{
// Is this function still needed?
if (!isdefined( level.vlavatars ) )
return;
foreach ( avatar in level.vlavatars )
{
if(!isdefined(avatar.animAlias) || !isdefined(avatar.animstate))
{
animdata = avatar GetAnimData(avatar.primaryweapon);
avatar use_animstate( animdata.alias, undefined, animdata.animstate );
}
}
}
start_lobby_anims()
{
// Is this function still needed?
if (!isdefined( level.vlavatars ) )
return;
foreach ( avatar in level.vlavatars )
{
if(!isdefined(avatar.animAlias) || !isdefined(avatar.animstate))
{
animdata = avatar GetAnimData(avatar.primaryweapon);
avatar use_animstate( animdata.alias, undefined, animdata.animstate );
}
}
}
start_cao_anims()
{
// Is this function still needed?
if (!isdefined( level.vlavatars ) )
return;
foreach ( avatar in level.vlavatars )
{
if(!isdefined(avatar.animAlias) || !isdefined(avatar.animstate))
{
animdata = avatar GetAnimData(avatar.primaryweapon);
avatar use_animstate( animdata.alias, undefined, animdata.animstate );
}
}
}
//************************************************************************************************************
//************** Procedural Camera **************************************************************************
//************************************************************************************************************
/*
* returns an array of points to move a camera from start to end without colliding with obstacles
* start, end are vectors
* obstacles is an array with each entry being an array with the center and radius of the obstacle
*
*
*/
find_best_cam_path( _start, _end, obstacles )
{
path = [];
path[0] = _start;
path[1] = _end;
safetycount = 20;
modified = true;
while ( modified && ( safetycount > 0 ) )
{
safetycount--;
modified = false;
newpath = [];
newpath[newpath.size] = path[0];
bail = false;
bailidx = 0;
for ( i=0; ( i< (path.size-1) ) && !bail; i++ )
{ // for each subpath
collision = true;
start = path[i];
end = path[i+1];
while (collision)
{
collision = false;
best = undefined;
best_trace = undefined;
foreach ( obstacle in obstacles )
{
trace = trace2d( start, end, obstacle );
if ( trace["intersect"] )
{
if ( ( distance2D( newpath[newpath.size-1], trace["closestpoint"] ) > 0.1 ) &&
( distance2D( end, trace["closestpoint"] ) > 0.1 ) )
{ // ignoring new closestpoints too close to original points
collision = true;
if ( !IsDefined(best_trace) || ( best_trace[ "radratio" ] > trace["radratio"] ) )
{ // pick the intersection that is closest to the center of the circle
best = obstacle;
best_trace = trace;
}
}
}
}
if ( collision )
{ // use the best intersection to split the line
modified = true;
// if the best intersection is close to an endpoint, we need to move the endpoint, which means we need to break all the way out
if ( length2D( start, best["center"] ) < best[ "radius" ] )
{ // need to move start
start = move_outside_circle( start, best );
assert( i > 0 ); // can't change original starting point
newpath[newpath.size-1] = start; // modify original position
collision = false; // force bail out of this loop
bail = true; // force bail of outer loop
bailidx = i+1;
}
else if ( length2D( end, best["center"] ) < best[ "radius" ] )
{ // need to move end
end = move_outside_circle( end, best );
assert( (i+1) < path.size ); // can't change original ending point
newpath[newpath.size] = end; // modify original position
collision = false; // force bail out of this loop
bail = true; // force bail of outer loop
bailidx = i+2;
}
else
{ // subdivide ( note that start is already on newpath )
newpath[newpath.size] = best_trace["closestpoint"];
newpath[newpath.size] = end;
collision = false; // since we've added entries, we need to stop testing here (no loop needed)
}
}
else
{ // just add the end point to newpath
newpath[newpath.size] = end;
}
}
}
if ( bail )
{ // add the remainder of path to newpath, since we modified an internal path element
for ( i = bailidx; i < path.size; i++ )
{
newpath[newpath.size] = path[i];
}
}
path = newpath;
}
return path;
}
move_outside_circle( point, circle )
{
center = circle["center"];
radius = circle["radius"];
dir = VectorNormalize( ( point[0] - center[0], point[1] - center[1], 0 ) );
point = (center[0] + radius*dir[0], center[1] + radius*dir[1], point[2] );
return point;
}
trace2d( start, end, circle )
{
pathbias = OBSTACLE_PATHBIAS;
center = circle["center"];
radius = circle["radius"];
pathradius = radius + pathbias;
vec2d = ( end[0] - start[0], end[1] - start[1], 0 );
dir = VectorNormalize( vec2d );
dist = Length2D( vec2d );
s2c = ( center[0] - start[0], center[1] - start[1], 0 );
off = VectorDot( dir, s2c );
if ( off < 0 )
off = 0.0;
else if ( off > dist )
off = dist;
closestpoint = ( start[0] + off*dir[0], start[1] + off*dir[1], 0 );
fraction = off/dist;
normal = ( closestpoint[0] - center[0], closestpoint[1] - center[1], 0 );
dist = Length2D( normal );
intersect = false;
radratio = 1.0;
if ( dist < radius )
{
intersect = true;
normal = VectorNormalize( normal );
// we'll pick a point that is a little further away so we don't re-intersect the same cylinder
closestpoint = ( center[0] + pathradius*normal[0], center[1] + pathradius*normal[1], start[2] + (fraction * (end[2] - start[2])) );
radratio = dist/radius;
}
retval = [];
retval[ "intersect" ] = intersect;
retval[ "fraction" ] = fraction;
retval[ "closestpoint" ] = closestpoint;
retval[ "radratio" ] = radratio;
return retval;
}
calc_new_pos( prv_point, speed, goal )
{
dist = Distance( prv_point, goal );
if ( dist > speed )
{
dir = VectorNormalize( goal - prv_point );
goal = prv_point + speed*dir;
}
return goal;
}
lookahead_path( prvIdx, prv_point, speed, lookahead, path )
{
// find the closes point on the current segment
start = path[prvIdx];
if ( ( prvIdx + 1 ) >= path.size )
{ // at end, so lookahead is the endpoint
return [ prvIdx, calc_new_pos( prv_point, speed, path[prvIdx] ) ];
}
end = path[prvIdx+1];
len = Distance( start, end );
dir = VectorNormalize( end - start );
dist_on_path = VectorDot( dir, prv_point-start );
if (dist_on_path < 0)
dist_on_path = 0;
if (dist_on_path > len)
dist_on_path = len;
pnt_on_path = start + dist_on_path*dir;
lookahead_left = lookahead;
dist_in_seg = len - dist_on_path;
lookahead_point = path[path.size-1]; // to handle fall through case
while (lookahead_left > 0)
{
if ( dist_in_seg > lookahead_left )
{
lookahead_point = pnt_on_path + lookahead_left*dir;
lookahead_left = 0;
}
else
{ // at end, so lookahead is the endpoint
if ( ( prvIdx + 1 ) >= path.size )
{
lookahead_point = path[prvIdx];
lookahead_left = 0;
}
lookahead_left -= dist_in_seg;
prvIdx++;
pnt_on_path = path[prvIdx];
}
}
return [ prvIdx, calc_new_pos( prv_point, speed, lookahead_point ) ];
}
init_path_traversal( camera )
{
camera.distanceOnPath = 0;
camera.pathIdx = 0;
camera.distOnPathSegment = 0;
camera.pathSpeed = 0;
idealSpeed = camera.pathInfo_len/camera.PATH_IDEALTIME;
if (idealSpeed < camera.PATH_MINSPEED)
idealSpeed = camera.PATH_MINSPEED;
if (idealSpeed > camera.PATH_MAXSPEED)
idealSpeed = camera.PATH_MAXSPEED;
camera.pathAccel = 0.05*idealSpeed/camera.PATH_ACCEL_TIME;
camera.pathDeccel = 0.05*idealSpeed/camera.PATH_DECCEL_TIME;
camera.pathTgtSpeed = idealSpeed;
camera.pathAccelMode = 1;
camera.pathInfo_t = 0;
camera.pathInfo_totalt = camera.PATH_IDEALTIME;
steps = (camera.PATH_DECCEL_TIME/0.05);
dist = 0;
speed = idealSpeed;
// brute force calculation of distance travelled during decel
for (i=0; i<steps; i++ )
{
speed -= camera.pathDeccel;
if (speed < camera.PATH_MINDECCELSPEED)
speed = camera.PATH_MINDECCELSPEED;
dist += speed;
}
camera.pathStartDeccelDist = camera.pathInfo_len - dist;
camera.pitch = camera.pathInfo_startPitch;
}
update_path_speed( camera )
{
if (camera.distanceOnPath < camera.pathStartDeccelDist)
{
camera.pathSpeed += camera.pathAccel;
if (camera.pathSpeed > camera.pathTgtSpeed)
camera.pathSpeed = camera.pathTgtSpeed;
}
else
{
camera.pathSpeed -= camera.pathDeccel;
if (camera.pathSpeed < camera.PATH_MINDECCELSPEED)
camera.pathSpeed = camera.PATH_MINDECCELSPEED;
}
}
init_path_constants( camera )
{
camera.PATH_MAXSPEED = 0.05*300;
camera.PATH_MINSPEED = 0.05*36;
camera.PATH_MINDECCELSPEED = 0.05*6;
camera.PATH_IDEALTIME = 0.5;
camera.PATH_ACCEL_TIME = 0.15*camera.PATH_IDEALTIME;
camera.PATH_DECCEL_TIME = 0.15*camera.PATH_IDEALTIME;
camera.pathMaxRotZ = 0.05*90;
camera.pathMaxRotX = 0.05*90;
}
build_path_info( camera, camParams, start_loc, end_loc, endAngles )
{
path = find_best_cam_path( camera.origin, end_loc, camera.obstacles );
camera.path = path;
len = 0;
foreach ( idx, node in camera.path )
{
if (idx > 0)
{
len += Distance( camera.path[idx], camera.path[idx-1] );
}
}
camera.pathInfo_t = 0;
camera.pathInfo_totalt = camera.PATH_IDEALTIME;
camera.pathInfo_len = len;
camera.pathInfo_startAim = AnglesToForward( camera.angles );
camera.pathInfo_endAim = AnglesToForward( endAngles );
// NewTargetPosition = FindNewTargetPos(endEnt.camera_helper.angles,endEnt.camera_helper.origin,endEnt.camera_lookat.origin);
/*
if ( IsDefined( camParams ) )
{
camera.pathInfo_endAim = calc_target_dir( endEnt.camera_helper.origin, NewTargetPosition, camParams );
}
else
{
camera.pathInfo_endAim = VectorNormalize( NewTargetPosition - endEnt.camera_helper.origin );
}
*/
// endAngles = VectorToAngles( camera.pathInfo_endAim );
camera.pathInfo_startPitch = AngleClamp180(camera.angles[0]); // we will lerp the pitch to the endpitch
camera.pathInfo_curStartPitch = camera.pathInfo_startPitch; // tracks the moving pitch value to prevent seesawing
camera.pathInfo_endPitch = AngleClamp180(endAngles[0]);
camera.pathInfo_startYaw = AngleClamp180(camera.angles[1]);
camera.pathInfo_endYaw = AngleClamp180(endAngles[1]);
camera.pathInfo_start_loc = start_loc;
camera.pathInfo_end_loc = end_loc;
camera.pathInfo_velocity = (0,0,0);
baseTravelDir = VectorNormalize( camera.pathInfo_end_loc - camera.pathInfo_start_loc );
startDP = VectorDot( baseTravelDir, camera.pathInfo_startAim );
endDP = VectorDot( baseTravelDir, camera.pathInfo_endAim );
path_mode = 0; // standard mode
if ( ( endDP < -0.707 ) && ( startDP < -0.707 ) )
path_mode = 1; // leave camera pointint at old target until the new target is close to the fov
camera.pathInfo_mode = path_mode;
init_path_traversal( camera );
}
FindNewTargetPos(CamAngles,CamOrigin,OldTargetOrigin)
{
//// trying to move the target to match the angles of the camera ent in radiant.
Vec3CamDir = AnglesToForward(CamAngles);
Cam2Tgt = OldTargetOrigin - CamOrigin;
Dist2Tgt = VectorDot(Cam2Tgt,Vec3CamDir);
NewTargetPosition = CamOrigin + (Vec3CamDir * Dist2Tgt);
return NewTargetPosition;
}
sigmoid( x, maxx )
{
// x comes in (0-1)
xoffset = -0.5;
x += xoffset; // now it is -0.5 to 0.5
x *= 2*maxx; // now it is -maxx to maxx
scale = sqrt( 1 + maxx*maxx )/(2*maxx); // used to keep the result from -0.5 to 0.5
offset = 0.5; // this will move the result to 0 to 1
value = scale*( x/sqrt(1 + x*x) ) + offset;
assert( value >= 0 && value <= 1 );
return value;
}
lerp_towards_desiredAngle( camera, desiredAngles )
{
desiredX = AngleClamp180(desiredAngles[0]);
currentX = AngleClamp180(camera.angles[0]);
dZ = AngleClamp180(desiredAngles[1] - camera.angles[1]);
dX = AngleClamp180(desiredX - currentX);
if ( dZ < -1*camera.pathMaxRotZ )
dZ = -1*camera.pathMaxRotZ;
if ( dZ > camera.pathMaxRotZ )
dZ = camera.pathMaxRotZ;
if ( dX < -1*camera.pathMaxRotX )
dX = -1*camera.pathMaxRotX;
if ( dX > camera.pathMaxRotX )
dX = camera.pathMaxRotX;
deltaAngles = ( dX, dZ, 0 );
camera.angles = camera.angles + deltaAngles;
if ((abs(dX) < 0.1) && (abs(dZ) < 0.1))
return true;
else
return false;
}
update_camera_angles_on_path( camera, camParams )
{
fraction = camera.pathInfo_t/camera.pathInfo_totalt;
fraction = sigmoid( fraction, 2 );
// One exception is if we are moving in a direction opposite our final direction
desiredAngles = camera.angles;
// we lerp our pitch between our start and end pitches. If the desired pitch is closer to the end, then we take it
lerpedPitch = fraction*(camera.pathInfo_endPitch - camera.pathInfo_startPitch) + camera.pathInfo_startPitch;
// we lerp our yaw range between our start and end yaw.
// startYaw moves to endYaw as we move along path
startYaw = camera.pathInfo_startYaw + fraction*(camera.pathInfo_endYaw - camera.pathInfo_startYaw);
desiredYaw = camera.angles[1] + AngleClamp180( startYaw - camera.angles[1] );
desiredAngles = ( lerpedPitch, desiredYaw, desiredAngles[2] );
return lerp_towards_desiredAngle( camera, desiredAngles );
}
update_camera_position_on_path( camera )
{
fraction = camera.pathInfo_t/camera.pathInfo_totalt;
fraction = sigmoid( fraction, 2 );
distToTravel = fraction*camera.pathInfo_len;
camera.pathIdx = 0;
camera.distOnPathSegment = 0;
camera.distanceOnPath = 0;
while ( distToTravel > 0 )
{
curSegLen = Distance( camera.path[camera.pathIdx], camera.path[camera.pathIdx+1] );
remainingLen = curSegLen - camera.distOnPathSegment;
if (remainingLen > distToTravel)
{
camera.distOnPathSegment += distToTravel;
neworigin = camera.path[camera.pathIdx] + camera.distOnPathSegment*VectorNormalize( camera.path[camera.pathIdx+1] - camera.path[camera.pathIdx] );
camera.pathInfo_velocity = neworigin - camera.origin;
camera.origin = neworigin;
camera.distanceOnPath += distToTravel;
distToTravel = 0;
}
else
{
distToTravel -= remainingLen;
camera.pathIdx++;
if (camera.pathIdx >= (camera.path.size - 1))
{ // end of the path
if ( camera.pathIdx < camera.path.size )
neworigin = camera.path[camera.pathIdx];
else
neworigin = camera.path[camera.path.size-1];
camera.pathInfo_velocity = neworigin - camera.origin;
camera.origin = neworigin;
camera.distanceOnPath = camera.pathInfo_len;
distToTravel = 0;
}
else
{
camera.distanceOnPath += remainingLen;
camera.distOnPathSegment = 0;
}
}
}
}
update_camera_on_path( camera, camParams )
{
finished = false;
camera.pathInfo_t += 0.05;
if ( camera.pathInfo_t >= camera.pathInfo_totalt )
{
camera.pathInfo_t = camera.pathInfo_totalt;
finished = true;
camera.pathInfo_velocity = (0,0,0);
}
//update_path_speed( camera );
update_camera_position_on_path( camera );
update_camera_angles_on_path( camera, camParams );
return finished;
}
get_target_from_avatar( avatar )
{
tag = "j_neck";
target = avatar GetTagOrigin( tag );
return target;
}
calc_f_from_avatar( avatar )
{
// tag_camera_loc_vec3 = avatar GetTagOrigin("TAG_STOWED_BACK");
// tag_camera_angles_vec3 = avatar GetTagAngles("TAG_STOWED_BACK");
CameraData = RotateAvatarTagCamera(avatar);
tag_camera_loc_vec3 = CameraData.camera_tag_origin;
tag_camera_angles_vec3 = CameraData.camera_tag_angles;
target = get_target_from_avatar( avatar );
cam_origin = tag_camera_loc_vec3;
cam_lookat = tag_camera_loc_vec3 + (anglestoforward(tag_camera_angles_vec3) * 64);
// NewTargetPosition = FindNewTargetPos(avatar.avatar_spawnpoint.camera_helper.angles,cam_origin, cam_lookat);
return calc_f( cam_origin, cam_lookat, target );
}
calc_f_from_avatar_spawnpoint( avatar_spawnpoint )
{
// this won't get us he camera look at anymore. Now based on animation bone location
target = avatar_spawnpoint.origin;
cam_origin = avatar_spawnpoint.camera_helper.origin;
cam_lookat = avatar_spawnpoint.camera_lookat.origin;
return calc_f( cam_origin, cam_lookat, target );
}
calc_f( cam_origin, cam_lookat, target )
{
P = cam_lookat;
C = cam_origin;
T = target;
result = [];
X = VectorNormalize( VectorCross( P-C, (0,0,1) ) );
Z = VectorNormalize( VectorCross( X, P-C ) );
CT =T - C;
Tx = T - (VectorDot( Z, CT )*Z);
Tz = T - (VectorDot( X, CT )*X);
Dx = Distance( Tx, P );
Hx = Distance( Tx, C );
fx = Dx/Hx;
sx = 1;
if ( VectorDot( CT, X ) < 0 )
{
sx = -1;
}
result["fx"] = fx;
result["sx"] = sx;
Dz = Distance( Tz, P );
Hz = Distance( Tz, C );
fz = Dz/Hz;
sz = 1;
if ( VectorDot( CT, Z ) < 0 )
{
sz = -1;
}
result["fz"] = fz;
result["sz"] = sz;
return result;
}
calc_f_fromscreen( ex, ez )
{
FOV = GetDvarFloat("cg_fov", 45 ) * GetDvarFloat( "cg_fovScale", 1.0 );
aspectz = 1.0;
dfov = tan( FOV );
result = [];
dx = dfov * abs(ex);
sx = 1;
if ( ex < 0 )
sx = -1;
fx = dx / sqrt( 1 - dx*dx );
result["sx"] = sx;
result["fx"] = fx;
dz = aspectz * dfov * abs(ez);
sz = 1;
if ( ez < 0 )
sz = -1;
fz = dz / sqrt( 1 - dz*dz );
result["sz"] = sz;
result["fz"] = fz;
return result;
}
calc_cam_lookat( fparams, cam_origin, target )
{
C = cam_origin;
T = target;
CT = T-C;
X = VectorNormalize( VectorCross( CT, (0,0,1) ) );
Z = VectorNormalize( VectorCross( X, CT ) );
CTx = CT - (VectorDot( CT, Z ) * Z );
Hx = Length( CTx );
fx = fparams["fx"];
sx = fparams["sx"];
Dx = Hx*fx;
hx = Hx * fx*fx;
lx = Hx*fx*sqrt( 1 - (fx*fx) );
TPx = hx*CTx +lx*X;
CTz = CT - (VectorDot( CT, X ) * X );
Hz = Length( CTz );
fz = fparams["fz"];
sz = fparams["sz"];
Dz = Hz*fz;
hz = Hz * fz*fz;
lz = Hz*fz*sqrt( 1 - (fz*fz) );
TPz = hz*CTz +lz*Z;
P = T + sx*TPx + sz*TPz;
return P;
}
debug_draw_path( path )
{
color = (1,1,1);
prvpoint = path[0];
newpoint = prvpoint;
prvIdx = 0;
speed = 10;
lookahead = 30;
if (level.use_lookahead)
{
while ( true )
{
newrecord = lookahead_path( prvIdx, prvpoint, speed, lookahead, path );
prvIdx = newrecord[0];
newpoint = newrecord[1];
if (distance(prvpoint, newpoint) < 0.1)
break;
line( prvpoint, newpoint, color, 1, true, 1 );
prvpoint = newpoint;
if ( prvIdx >= path.size )
break;
}
}
else
{
for ( i=0; i<(path.size-1); i++ )
{
line( path[i], path[i+1], color, 1, true, 1 );
}
}
}
debug_draw_obstacles( obstacles )
{
color = (1,0.5,0);
foreach (obstacle in obstacles)
{
center = obstacle["center"];
radius = obstacle["radius"];
Cylinder( center, center + (0,0,100), radius, color, true, 1 );
}
}
debug_draw_aim( camera )
{
cntsBtnDraws = 1;
cnt = cntsBtnDraws;
aimLen = 36;
init_path_traversal( camera );
camera.target_from_avatar = get_target_from_avatar( camera.targetAvatar );
while ( !update_camera_on_path( camera ) )
{
target = camera.target_from_avatar;
cam_target = calc_cam_lookat( camera.fparams, camera.origin, target );
cnt--;
if (cnt <= 0)
{
cnt = cntsBtnDraws;
line( camera.origin, camera.origin + aimLen*AnglesToForward( camera.angles ), (1,0,0), 1, true, 1 );
line( camera.origin, cam_target, (1,0.5,0.5), 1, true, 1 );
}
}
// ensure we're clamped into a good range for all camera angles
camera.angles = ( AngleClamp180( camera.angles[0] ), AngleClamp180( camera.angles[1] ), AngleClamp180( camera.angles[2] ) );
camera DontInterpolate();
}
test_pathing( camera, startEnt, endEnt, obstacles )
{
level notify( "stop_test_pathing" );
level endon( "stop_test_pathing" );
player_points = GetEntArray( "player_pos", "targetname" );
avatar = endEnt.spawned_avatar;
CameraData = RotateAvatarTagCamera(avatar);
tag_camera_loc_vec3 = CameraData.camera_tag_origin;
tag_camera_angles_vec3 = CameraData.camera_tag_angles;
end = tag_camera_loc_vec3;
angles = tag_camera_angles_vec3;
start = camera.origin;
StartLookAtLoc = start + (AnglesToForward(camera.angles) * 64);
EndLookAtLoc = end + (AnglesToForward(angles) * 64);
// start = startEnt.camera_helper.origin;
// startTarget = startEnt.camera_lookat.origin;
// startDir = startTarget - start;
// angles = VectorToAngles( startDir );
// end = endEnt.camera_helper.origin;
camera.origin = start;
camera.angles = angles;
camera.obstacles = obstacles;
init_path_constants( camera );
//path = find_best_cam_path( start, end, obstacles );
build_path_info( camera, undefined, camera.origin, end, angles );
camera.fparams = calc_f_from_avatar( avatar );
camera.targetAvatar = avatar;
while (true)
{
camera.origin = start;
camera.angles = angles;
line( start-(5,0,0), start+(5,0,0), (1,0,1) );
line( start-(0,5,0), start+(0,5,0), (1,0,1) );
line( start-(0,0,5), start+(0,0,5), (1,0,1) );
line( end-(5,0,0), end+(5,0,0), (1,1,0) );
line( end-(0,5,0), end+(0,5,0), (1,1,0) );
line( end-(0,0,5), end+(0,0,5), (1,1,0) );
line( start, StartLookAtLoc, (0,1,1) );
line( end, EndLookAtLoc, (0,1,1) );
debug_draw_path( camera.path );
debug_draw_obstacles( camera.obstacles );
debug_draw_aim( camera );
wait 0.05;
}
}
debug_pathing()
{
trigger = false;
player_points = GetEntArray( "player_pos", "targetname" );
foreach ( AvatarSpawn in player_points )
{
CameraTarget = GetEnt(AvatarSpawn.target,"targetname");
if(CameraTarget.script_noteworthy == "camera_target")
{
AvatarSpawn.camera_lookat = CameraTarget;
}
CameraEnt = GetEnt(CameraTarget.target,"targetname");
if(CameraEnt.script_noteworthy == "camera")
{
AvatarSpawn.camera_helper = CameraEnt;
CameraEnt.camera_goal = AvatarSpawn;
CameraEnt.camera_lookat = AvatarSpawn.camera_lookat;
}
}
fakecamera = spawn( "script_model", (0,0,0) );
fakecamera SetModel( "tag_player" );
level.use_lookahead = false;
startIdx = 0;
endIdx = 1;
obstaclemask = "111111111111111111";
radius = OBSTACLE_RADIUS;
while (true)
{
if ( self FragButtonPressed() )
{
while ( self FragButtonPressed() )
wait 0.05;
endIdx++;
if ( endIdx >= 12 )
endIdx = 0;
if (endIdx == startIdx)
{
endIdx++;
if ( endIdx >= 12 )
endIdx = 0;
}
trigger = true;
}
if ( self SecondaryOffhandButtonPressed() )
{
while ( self SecondaryOffhandButtonPressed() )
wait 0.05;
startIdx++;
if ( startIdx >= 12 )
startIdx = 0;
if (endIdx == startIdx)
{
startIdx++;
if ( startIdx >= 12 )
startIdx = 0;
}
trigger = true;
}
if (trigger)
{
trigger = false;
obstacles = [];
start_point = undefined;
end_point = undefined;
foreach (idx, player_point in player_points)
{
if ( /*( idx == startIdx ) || ( idx == endIdx ) || */ (GetSubStr( obstaclemask, idx, idx+1 ) == "0" ) )
continue;
obstacle = [];
obstacle["center"] = player_point.origin;
obstacle["radius"] = radius;
obstacles[obstacles.size] = obstacle;
if (player_point.script_noteworthy == ""+startIdx)
start_point = player_point;
if (player_point.script_noteworthy == ""+endIdx)
end_point = player_point;
}
thread test_pathing( fakecamera, start_point, end_point, obstacles );
}
wait 0.2;
}
}
debug_fly( camera )
{
level.debug_fly = true;
speed = 30;
latspeed = 10;
upspeed = 10;
angles = self GetUnNormalizedCameraMovement();
delta = self GetNormalizedMovement();
forward = AnglesToForward( angles );
up = AnglesToUp( angles );
right = AnglesToRight( angles );
deltaUp = 0;
if ( self AdsButtonPressed() )
deltaUp = -1;
else if ( self AttackButtonPressed() )
deltaUp = 1;
if ( self SecondaryOffhandButtonPressed() )
{
speed = speed * 0.1;
latspeed = latspeed * 0.1;
upspeed = upspeed * 0.1;
}
camera.angles = angles;
camera.origin = camera.origin + delta[0]*speed*forward + delta[1]*latspeed*right + deltaUp*upspeed*up;
}
vlobby_vegnette(opacity, material)
{
if ( !isDefined( self.vegnette ) )
{
self.vegnette = newClientHudElem( self );
self.vegnette.x = 0;
self.vegnette.y = 0;
self.vegnette setshader( material, 640, 480 );
self.vegnette.alignX = "left";
self.vegnette.alignY = "top";
self.vegnette.horzAlign = "fullscreen";
self.vegnette.vertAlign = "fullscreen";
self.vegnette.alpha = opacity;
}
//disable the vignette effect when opacity is set to "0" and the vegnette has already been enabled
if ( isDefined( self.vegnette ) && self.vegnette.alpha > 0 && opacity == 0)
{
self.vegnette setshader( material, 640, 480 );
self.vegnette.alpha = 0;
}
if ( isDefined( self.vegnette ) && self.vegnette.alpha < 1 && opacity == 1)
{
self.vegnette setshader( material, 640, 480 );
self.vegnette.alpha = 1;
}
}