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