4 #include <common/util.qh>
5 #include <common/constants.qh>
8 #include <common/stats.qh>
9 #include <common/weapons/_all.qh>
13 void viewloc_PlayerPhysics(entity this)
17 if(this.viewloc.goalentity == this.viewloc.enemy)
18 return; // we can't side-scroll in this case
20 vector old_movement = PHYS_CS(this).movement;
21 PHYS_CS(this).movement_x = old_movement_y;
22 if((this.viewloc.spawnflags & VIEWLOC_FREEMOVE) && !this.ladder_entity)
23 PHYS_CS(this).movement_y = old_movement_x;
25 PHYS_CS(this).movement_y = 0;
27 vector level_start, level_end;
28 level_start = this.viewloc.enemy.origin;
29 level_end = this.viewloc.goalentity.origin;
30 vector forward = vectoangles(normalize(level_end - level_start));
31 vector backward = vectoangles(normalize(level_start - level_end));
33 if((this.viewloc.spawnflags & VIEWLOC_FREEMOVE) && this.angles_y < 0 && !this.ladder_entity)
34 PHYS_CS(this).movement_y = -PHYS_CS(this).movement_y;
36 if(this.viewloc.spawnflags & VIEWLOC_FREEAIM)
39 PHYS_CS(this).movement_x = -PHYS_CS(this).movement_x;
43 if(PHYS_CS(this).movement_x < 0)
44 PHYS_CS(this).movement_x = -PHYS_CS(this).movement_x;
46 if(PHYS_CS(this).movement_x < 0) // left
47 this.angles_y = backward.y;
48 if(PHYS_CS(this).movement_x > 0) // right
49 this.angles_y = forward.y;
52 //if(!PHYS_INPUT_BUTTON_CROUCH(this) && !IS_DUCKED(this))
53 if(!(this.viewloc.spawnflags & VIEWLOC_FREEMOVE))
56 //PHYS_INPUT_BUTTON_CROUCH(this) = (old_movement_x < 0);
57 if (old_movement.x < 0)
58 PHYS_INPUT_BUTTON_CROUCH(this) = true;
60 if (old_movement.x < 0)
62 input_buttons |= BIT(4);
63 this.flags |= FL_DUCKED;
65 //else { input_buttons &= ~16; this.flags &= ~FL_DUCKED; }
74 void viewloc_SetTags(entity this)
76 if(this.viewloc && wasfreed(this.viewloc))
79 if(this.viewloc.entnum != this.tag_networkviewloc)
81 if(this.tag_networkviewloc == 0)
84 this.viewloc = findfloat(NULL, entnum, this.tag_networkviewloc);
88 vector CursorToWorldCoord(vector mpos)
90 vector wnear = cs_unproject(vec2(mpos)); // determine the world coordinate for the mouse cursor upon the near clip plane
91 vector wfar = cs_unproject(vec3(mpos.x, mpos.y, max_shot_distance)); // determine the world coordinate for the mouse cursor upon the far clip plane, with an outrageously large value as a workaround for dp.
92 traceline(wnear, wfar, MOVE_NOMONSTERS, NULL);
96 vector old_camera_angle = '0 0 0';
97 void viewloc_SetViewLocation()
99 entity view = CSQCModel_server2csqc(player_localentnum - 1);
101 entity viewloc_ent = view.viewloc;
102 if(viewloc_ent && !wasfreed(viewloc_ent) && viewloc_ent.enemy && viewloc_ent.goalentity)
104 bool have_sidescroll = (viewloc_ent.enemy != viewloc_ent.goalentity);
105 vector position_a = viewloc_ent.enemy.origin;
106 vector position_b = viewloc_ent.goalentity.origin;
107 vector camera_angle = '0 0 0';
108 vector camera_position;
110 /*TODO: have the camera only move when a player moves too much from the center of the camera
111 * basically the player would move around in a small "box" in the center of the screen with out changing the camera position or angles */
112 camera_position = vec_bounds_in(view.origin, position_a, position_b);
114 // use camera's angle when possible
115 if (!(viewloc_ent.spawnflags & VIEWLOC_CAM_NOANGLE)) {
116 camera_angle = viewloc_ent.enemy.movedir;
119 // a tracking camera follows the player when it leaves the world box
120 if ((viewloc_ent.spawnflags & VIEWLOC_CAM_TRACK) || !have_sidescroll) {
121 camera_angle = aim_vec (camera_position, view.origin);
124 // hard snap changes the angle as soon as it crosses over the nearest 90 degree mark
125 if (viewloc_ent.spawnflags & VIEWLOC_CAM_SNAP_HARD) {
126 camera_angle = angle_snap_vec(aim_vec(camera_position, view.origin), 90);
129 // tries to avoid snapping unless it *really* needs to
130 if (viewloc_ent.spawnflags & VIEWLOC_CAM_SNAP_CLOSE) {
131 // like hard snap, but don't snap angles yet.
132 camera_angle = aim_vec(camera_position, view.origin);
134 /* if the difference between the old and new angle is 60 degrees or more, switch angles.
135 * NOTE: bug/feature: this will use non-snaped angles for one frame.
136 * doing this results in less code, faster code, and a smoother transisition between angles.
138 float camera_angle_diff = max(camera_angle.y, old_camera_angle.y) - min(camera_angle.y, old_camera_angle.y);
140 if (60 <= camera_angle_diff) { // use new angles
141 old_camera_angle.y = angle_snap_f(camera_angle.y, 90);
142 } else { // use old angles
143 camera_angle.y = old_camera_angle.y;
147 //unlocking this allows the camera to look up and down. this also allows a top-down view.
148 if (!(viewloc_ent.spawnflags & VIEWLOC_CAM_SNAP_UNLOCK)) {
154 LOG_TRACE(vtos(camera_position));
155 LOG_TRACE(vtos(old_camera_angle));
156 LOG_TRACE(vtos(camera_angle));
159 freeze_org = getpropertyvec(VF_ORIGIN);
160 freeze_ang = getpropertyvec(VF_ANGLES);
161 setproperty(VF_ORIGIN, camera_position);
162 setproperty(VF_ANGLES, camera_angle);
165 return; // if spectating, don't replace angles or inputs!
167 if (have_sidescroll) {
168 vector view_angle = view.angles;
169 if (!(viewloc_ent.spawnflags & VIEWLOC_FREEAIM)) {
170 vector avatar_facing_dir;
171 // get the player's forward-facing direction, based on positions a and b
172 if (0 == input_movevalues.y) {
173 avatar_facing_dir = view_angle; // default to the previous values
174 } else if (0 > input_movevalues.y) { // left is forward
175 avatar_facing_dir = vectoangles(normalize(vec_to_max(position_b, position_a) - vec_to_min(position_b, position_a)));
176 } else { // right is forward
177 avatar_facing_dir = vectoangles(normalize(vec_to_min(position_b, position_a) - vec_to_max(position_b, position_a)));
179 view_angle.y = avatar_facing_dir.y; // snap avatar to look on along the correct axis
181 // if (0 == input_movevalues.x) look straight ahead
182 if (!(viewloc_ent.spawnflags & VIEWLOC_FREEMOVE)) {
183 if (0 > input_movevalues.x) { // look up
185 } else if (0 < input_movevalues.x) { // look down
190 vector mpos = CursorToWorldCoord(viewloc_mousepos);
191 mpos.x = view.origin.x; // replace the cursor's x position with the player's
192 view_angle = aim_vec(view.origin + view.view_ofs, mpos); // get new angles
194 view.angles_y = view_angle.y;
195 setproperty(VF_CL_VIEWANGLES, view_angle);
200 STATIC_INIT_LATE(viewloc_cursor)
202 // fix the mouse position on init so it isn't in the corner
203 viewloc_mousepos = '0.5 0 0' * autocvar_vid_conwidth + '0 0.5 0' * autocvar_vid_conheight;