]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/animdecide.qc
get rid of ANIMPRIO_STATIC, it was misused anyway
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / animdecide.qc
1 // player animation data for this model
2 // each vector is as follows:
3 // _x = startframe
4 // _y = numframes
5 // _z = framerate
6 .vector anim_die1; // player dies
7 .vector anim_die2; // player dies differently
8 .vector anim_draw; // player pulls out a weapon
9 .vector anim_duckwalk; // player walking while crouching
10 .vector anim_duckjump; // player jumping from a crouch
11 .vector anim_duckidle; // player idling while crouching
12 .vector anim_idle; // player standing
13 .vector anim_jump; // player jump
14 .vector anim_pain1; // player flinches from pain
15 .vector anim_pain2; // player flinches from pain, differently
16 .vector anim_shoot; // player shoots
17 .vector anim_taunt; // player taunts others (FIXME: no code references this)
18 .vector anim_run; // player running forward
19 .vector anim_runbackwards; // player running backward
20 .vector anim_strafeleft; // player shuffling left quickly
21 .vector anim_straferight; // player shuffling right quickly
22 .vector anim_forwardright; // player running forward and right
23 .vector anim_forwardleft; // player running forward and left
24 .vector anim_backright; // player running backward and right
25 .vector anim_backleft; // player running back and left
26 .vector anim_melee; // player doing the melee action
27 .vector anim_duck; // player doing the melee action
28 .vector anim_duckwalkbackwards;
29 .vector anim_duckwalkstrafeleft;
30 .vector anim_duckwalkstraferight;
31 .vector anim_duckwalkforwardright;
32 .vector anim_duckwalkforwardleft;
33 .vector anim_duckwalkbackright;
34 .vector anim_duckwalkbackleft;
35
36 void animdecide_init(entity e)
37 {
38         vector none = '0 0 0';
39         e.anim_die1 = animfixfps(e, '0 1 0.5', none); // 2 seconds
40         e.anim_die2 = animfixfps(e, '1 1 0.5', none); // 2 seconds
41         e.anim_draw = animfixfps(e, '2 1 3', none);
42         e.anim_duckwalk = animfixfps(e, '4 1 1', none);
43         e.anim_duckjump = animfixfps(e, '5 1 10', none);
44         e.anim_duckidle = animfixfps(e, '6 1 1', none);
45         e.anim_idle = animfixfps(e, '7 1 1', none);
46         e.anim_jump = animfixfps(e, '8 1 10', none);
47         e.anim_pain1 = animfixfps(e, '9 1 2', none); // 0.5 seconds
48         e.anim_pain2 = animfixfps(e, '10 1 2', none); // 0.5 seconds
49         e.anim_shoot = animfixfps(e, '11 1 5', none); // analyze models and set framerate
50         e.anim_taunt = animfixfps(e, '12 1 0.33', none);
51         e.anim_run = animfixfps(e, '13 1 1', none);
52         e.anim_runbackwards = animfixfps(e, '14 1 1', none);
53         e.anim_strafeleft = animfixfps(e, '15 1 1', none);
54         e.anim_straferight = animfixfps(e, '16 1 1', none);
55         e.anim_forwardright = animfixfps(e, '19 1 1', '16 1 1');
56         e.anim_forwardleft = animfixfps(e, '20 1 1', '15 1 1');
57         e.anim_backright = animfixfps(e, '21 1 1', '16 1 1');
58         e.anim_backleft  = animfixfps(e, '22 1 1', '15 1 1');
59         e.anim_melee = animfixfps(e, '23 1 1', '11 1 1');
60         e.anim_duckwalkbackwards = animfixfps(e, '24 1 1', '4 1 1');
61         e.anim_duckwalkstrafeleft = animfixfps(e, '25 1 1', '4 1 1');
62         e.anim_duckwalkstraferight = animfixfps(e, '26 1 1', '4 1 1');
63         e.anim_duckwalkforwardright = animfixfps(e, '27 1 1', '4 1 1');
64         e.anim_duckwalkforwardleft = animfixfps(e, '28 1 1', '4 1 1');
65         e.anim_duckwalkbackright = animfixfps(e, '29 1 1', '4 1 1');
66         e.anim_duckwalkbackleft  = animfixfps(e, '30 1 1', '4 1 1');
67
68         // these anims ought to stay until stopped explicitly by weaponsystem
69         e.aim_shoot_z = 0.001;
70         e.aim_melee_z = 0.001;
71 }
72
73 #define ANIMPRIO_IDLE 0
74 #define ANIMPRIO_ACTIVE 2
75 #define ANIMPRIO_DEAD 3
76
77 vector animdecide_getupperanim(entity e)
78 {
79         // is there an action?
80         vector outframe = '-1 0 0';
81         float t, a;
82         if(e.anim_upper_time >= e.anim_upper_implicit_time)
83         {
84                 a = e.anim_upper_action;
85                 t = e.anim_upper_time;
86         }
87         else
88         {
89                 a = e.anim_upper_implicit_action;
90                 t = e.anim_upper_implicit_time;
91         }
92         switch(a)
93         {
94                 case ANIMACTION_DRAW: outframe = e.anim_draw; break;
95                 case ANIMACTION_PAIN1: outframe = e.anim_pain1; break;
96                 case ANIMACTION_PAIN2: outframe = e.anim_pain2; break;
97                 case ANIMACTION_SHOOT: outframe = e.anim_shoot; break;
98                 case ANIMACTION_TAUNT: outframe = e.anim_taunt; break;
99                 case ANIMACTION_MELEE: outframe = e.anim_melee; break;
100         }
101         if(outframe_x >= 0)
102         {
103                 if(time <= t + outframe_y / outframe_z)
104                 {
105                         // animation is running!
106                         return vec3(outframe_x, t, ANIMPRIO_ACTIVE);
107                 }
108         }
109         // or, decide the anim by state
110         t = max(e.anim_time, e.anim_implicit_time);
111         // but all states are for lower body!
112         return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE);
113 }
114
115 vector animdecide_getloweranim(entity e)
116 {
117         // death etc.
118         if(e.anim_state & ANIMSTATE_FROZEN)
119                 return vec3(e.anim_idle_x, e.anim_time, ANIMPRIO_DEAD);
120         if(e.anim_state & ANIMSTATE_DEAD1)
121                 return vec3(e.anim_die1_x, e.anim_time, ANIMPRIO_DEAD);
122         if(e.anim_state & ANIMSTATE_DEAD2)
123                 return vec3(e.anim_die2_x, e.anim_time, ANIMPRIO_DEAD);
124
125         // is there an action?
126         vector outframe = '-1 0 0';
127         float t, a;
128         if(e.anim_lower_time >= e.anim_lower_implicit_time)
129         {
130                 a = e.anim_lower_action;
131                 t = e.anim_lower_time;
132         }
133         else
134         {
135                 a = e.anim_lower_implicit_action;
136                 t = e.anim_lower_implicit_time;
137         }
138         switch(a)
139         {
140                 case ANIMACTION_JUMP: if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR) { if(e.anim_state & ANIMSTATE_DUCK) outframe = e.anim_duckjump; else outframe = e.anim_jump; } break;
141         }
142         if(outframe_x >= 0)
143         {
144                 if(time <= t + outframe_y / outframe_z)
145                 {
146                         // animation is running!
147                         return vec3(outframe_x, t, ANIMPRIO_ACTIVE);
148                 }
149         }
150         // or, decide the anim by state
151         t = max(e.anim_time, e.anim_implicit_time);
152         if(e.anim_state & ANIMSTATE_DUCK)
153         {
154                 if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR)
155                         return vec3(e.anim_duckjump_x, 0, ANIMPRIO_ACTIVE); // play the END of the jump anim
156                 else switch(e.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT))
157                 {
158                         case ANIMIMPLICITSTATE_FORWARD:
159                                 return vec3(e.anim_duckwalk_x, t, ANIMPRIO_ACTIVE);
160                         case ANIMIMPLICITSTATE_BACKWARDS:
161                                 return vec3(e.anim_duckwalkbackwards_x, t, ANIMPRIO_ACTIVE);
162                         case ANIMIMPLICITSTATE_RIGHT:
163                                 return vec3(e.anim_duckwalkstraferight_x, t, ANIMPRIO_ACTIVE);
164                         case ANIMIMPLICITSTATE_LEFT:
165                                 return vec3(e.anim_duckwalkstrafeleft_x, t, ANIMPRIO_ACTIVE);
166                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT:
167                                 return vec3(e.anim_duckwalkforwardright_x, t, ANIMPRIO_ACTIVE);
168                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT:
169                                 return vec3(e.anim_duckwalkforwardleft_x, t, ANIMPRIO_ACTIVE);
170                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT:
171                                 return vec3(e.anim_duckwalkbackright_x, t, ANIMPRIO_ACTIVE);
172                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT:
173                                 return vec3(e.anim_duckwalkbackleft_x, t, ANIMPRIO_ACTIVE);
174                         default:
175                                 return vec3(e.anim_duckidle_x, t, ANIMPRIO_ACTIVE);
176                 }
177         }
178         else
179         {
180                 if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR)
181                         return vec3(e.anim_jump_x, 0, ANIMPRIO_ACTIVE); // play the END of the jump anim
182                 else switch(e.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT))
183                 {
184                         case ANIMIMPLICITSTATE_FORWARD:
185                                 return vec3(e.anim_run_x, t, ANIMPRIO_ACTIVE);
186                         case ANIMIMPLICITSTATE_BACKWARDS:
187                                 return vec3(e.anim_runbackwards_x, t, ANIMPRIO_ACTIVE);
188                         case ANIMIMPLICITSTATE_RIGHT:
189                                 return vec3(e.anim_straferight_x, t, ANIMPRIO_ACTIVE);
190                         case ANIMIMPLICITSTATE_LEFT:
191                                 return vec3(e.anim_strafeleft_x, t, ANIMPRIO_ACTIVE);
192                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT:
193                                 return vec3(e.anim_forwardright_x, t, ANIMPRIO_ACTIVE);
194                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT:
195                                 return vec3(e.anim_forwardleft_x, t, ANIMPRIO_ACTIVE);
196                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT:
197                                 return vec3(e.anim_backright_x, t, ANIMPRIO_ACTIVE);
198                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT:
199                                 return vec3(e.anim_backleft_x, t, ANIMPRIO_ACTIVE);
200                         default:
201                                 return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE);
202                 }
203         }
204         // can't get here
205 }
206
207 void animdecide_setimplicitstate(entity e, float onground)
208 {
209         float s;
210         s = 0;
211
212         makevectors(e.angles);
213         vector v;
214         v_x = e.velocity * v_forward;
215         v_y = e.velocity * v_right;
216
217         // we want to match like this:
218         // the 8 directions shall be "evenly spaced"
219         // that means, the forward key includes anything from -67.5 to +67.5 degrees
220         // which then means x > |y| * cot(3pi/8)
221         //
222         // BUT, the engine's clip-movement-to-keyboard function uses 0.5 here,
223         // which would be an angle range from -63.43 to +63.43 degrees, making
224         // it slightly less likely to "hit two keys at once", so let's do this
225         // here too
226
227         if(vlen(v) > 10)
228         {
229                 if(v_x >  fabs(v_y) * 0.5)
230                         s |= ANIMIMPLICITSTATE_FORWARD;
231                 if(v_x < -fabs(v_y) * 0.5)
232                         s |= ANIMIMPLICITSTATE_BACKWARDS;
233                 if(v_y >  fabs(v_x) * 0.5)
234                         s |= ANIMIMPLICITSTATE_RIGHT;
235                 if(v_y < -fabs(v_x) * 0.5)
236                         s |= ANIMIMPLICITSTATE_LEFT;
237         }
238         if(!onground)
239                 s |= ANIMIMPLICITSTATE_INAIR;
240
241         // detect some kinds of otherwise misdetected jumps (ground to air transition)
242         // NOTE: currently, in CSQC this is the only jump detection, as the explicit jump action is never called!
243         if(!(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR) && (s & ANIMIMPLICITSTATE_INAIR))
244         {
245                 e.anim_lower_implicit_action = ANIMACTION_JUMP;
246                 e.anim_lower_implicit_time = time;
247         }
248
249         if(s != e.anim_implicit_state)
250         {
251                 e.anim_implicit_state = s;
252                 e.anim_implicit_time = time;
253         }
254 }
255 void animdecide_setframes(entity e, float support_blending, .float fld_frame, .float fld_frame1time, .float fld_frame2, .float fld_frame2time)
256 {
257         // _x: frame
258         // _y: start time
259         // _z: priority
260         vector upper = animdecide_getupperanim(e);
261         vector lower = animdecide_getloweranim(e);
262         //print("UPPER: ", vtos(upper), ", LOWER: ", vtos(lower), "\n");
263         if(upper_z > lower_z)
264                 lower = upper;
265         else if(lower_z > upper_z)
266                 upper = lower;
267         if(support_blending)
268         {
269                 if(e.frame1time != upper_y || e.frame2time != lower_y)
270                         BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
271                 e.fld_frame = upper_x;
272                 e.fld_frame1time = upper_y;
273                 e.fld_frame2 = lower_x;
274                 e.fld_frame2time = lower_y;
275         }
276         else
277         {
278                 if(e.frame1time != upper_y)
279                         BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
280                 e.fld_frame = upper_x;
281                 e.fld_frame1time = upper_y;
282         }
283 }
284
285 void animdecide_setstate(entity e, float newstate, float restart)
286 {
287         if(!restart)
288                 if(newstate == e.anim_state)
289                         return;
290         e.anim_state = newstate;
291         e.anim_time = time;
292 }
293 void animdecide_setaction(entity e, float action, float restart)
294 {
295         if(action < 0)
296         {
297                 if(!restart)
298                         if(action == e.anim_lower_action)
299                                 return;
300                 e.anim_lower_action = action;
301                 e.anim_lower_time = time;
302         }
303         else
304         {
305                 if(!restart)
306                         if(action == e.anim_upper_action)
307                                 return;
308                 e.anim_upper_action = action;
309                 e.anim_upper_time = time;
310         }
311 }