]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/animdecide.qc
Merge branch 'Mario/vaporizer_damage' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / animdecide.qc
1 #if defined(CSQC)
2         #include "../dpdefs/csprogsdefs.qh"
3         #include "animdecide.qh"
4 #elif defined(MENUQC)
5 #elif defined(SVQC)
6         #include "../dpdefs/progsdefs.qh"
7     #include "../dpdefs/dpextensions.qh"
8     #include "util.qh"
9     #include "animdecide.qh"
10     #include "../server/defs.qh"
11 #endif
12
13 bool monsters_animoverride(entity e)
14 {
15         int monster_id = 0;
16         for(int i = MON_FIRST; i <= MON_LAST; ++i)
17         {
18                 entity mon = get_monsterinfo(i);
19
20                 //if(substring(e.model, 0, strlen(mon.model) - 4) == substring(mon.model, 0, strlen(mon.model) - 4))
21                 if(e.model == mon.model)
22                 {
23                         monster_id = i;
24                         break;
25                 }
26         }
27
28         if(!monster_id) { return false; }
29
30         MON_ACTION(monster_id, MR_ANIM);
31
32         vector none = '0 0 0';
33         e.anim_duckwalk = e.anim_walk;
34         e.anim_duckjump = animfixfps(e, '5 1 10', none);
35         e.anim_duckidle = e.anim_idle;
36         e.anim_jump = animfixfps(e, '8 1 10', none);
37         e.anim_taunt = animfixfps(e, '12 1 0.33', none);
38         e.anim_runbackwards = e.anim_run;
39         e.anim_strafeleft = e.anim_run;
40         e.anim_straferight = e.anim_run;
41         e.anim_forwardright = e.anim_run;
42         e.anim_forwardleft = e.anim_run;
43         e.anim_backright = e.anim_run;
44         e.anim_backleft  = e.anim_run;
45         e.anim_duckwalkbackwards = e.anim_walk;
46         e.anim_duckwalkstrafeleft = e.anim_walk;
47         e.anim_duckwalkstraferight = e.anim_walk;
48         e.anim_duckwalkforwardright = e.anim_walk;
49         e.anim_duckwalkforwardleft = e.anim_walk;
50         e.anim_duckwalkbackright = e.anim_walk;
51         e.anim_duckwalkbackleft  = e.anim_walk;
52
53         // these anims ought to stay until stopped explicitly by weaponsystem
54         e.anim_shoot_z = 0.001;
55         e.anim_melee_z = 0.001;
56
57         return true;
58 }
59
60 void animdecide_load_if_needed(entity e)
61 {
62         if(e.modelindex == e.animdecide_modelindex)
63                 return;
64         e.animdecide_modelindex = e.modelindex;
65
66         if(substring(e.model, 0, 16) == "models/monsters/")
67         {
68                 if(monsters_animoverride(e))
69                         return;
70         }
71
72         vector none = '0 0 0';
73         e.anim_die1 = animfixfps(e, '0 1 0.5', none); // 2 seconds
74         e.anim_die2 = animfixfps(e, '1 1 0.5', none); // 2 seconds
75         e.anim_draw = animfixfps(e, '2 1 3', none);
76         e.anim_duckwalk = animfixfps(e, '4 1 1', none);
77         e.anim_duckjump = animfixfps(e, '5 1 10', none);
78         e.anim_duckidle = animfixfps(e, '6 1 1', none);
79         e.anim_idle = animfixfps(e, '7 1 1', none);
80         e.anim_jump = animfixfps(e, '8 1 10', none);
81         e.anim_pain1 = animfixfps(e, '9 1 2', none); // 0.5 seconds
82         e.anim_pain2 = animfixfps(e, '10 1 2', none); // 0.5 seconds
83         e.anim_shoot = animfixfps(e, '11 1 5', none); // analyze models and set framerate
84         e.anim_taunt = animfixfps(e, '12 1 0.33', none);
85         e.anim_run = animfixfps(e, '13 1 1', none);
86         e.anim_runbackwards = animfixfps(e, '14 1 1', none);
87         e.anim_strafeleft = animfixfps(e, '15 1 1', none);
88         e.anim_straferight = animfixfps(e, '16 1 1', none);
89         e.anim_forwardright = animfixfps(e, '19 1 1', '16 1 1');
90         e.anim_forwardleft = animfixfps(e, '20 1 1', '15 1 1');
91         e.anim_backright = animfixfps(e, '21 1 1', '16 1 1');
92         e.anim_backleft  = animfixfps(e, '22 1 1', '15 1 1');
93         e.anim_melee = animfixfps(e, '23 1 1', '11 1 1');
94         e.anim_duckwalkbackwards = animfixfps(e, '24 1 1', '4 1 1');
95         e.anim_duckwalkstrafeleft = animfixfps(e, '25 1 1', '4 1 1');
96         e.anim_duckwalkstraferight = animfixfps(e, '26 1 1', '4 1 1');
97         e.anim_duckwalkforwardright = animfixfps(e, '27 1 1', '4 1 1');
98         e.anim_duckwalkforwardleft = animfixfps(e, '28 1 1', '4 1 1');
99         e.anim_duckwalkbackright = animfixfps(e, '29 1 1', '4 1 1');
100         e.anim_duckwalkbackleft  = animfixfps(e, '30 1 1', '4 1 1');
101
102         // these anims ought to stay until stopped explicitly by weaponsystem
103         e.anim_shoot_z = 0.001;
104         e.anim_melee_z = 0.001;
105 }
106
107 const float ANIMPRIO_IDLE = 0;
108 const float ANIMPRIO_ACTIVE = 1;
109 const float ANIMPRIO_CROUCH = 2;
110 const float ANIMPRIO_DEAD = 3;
111
112 vector animdecide_getupperanim(entity e)
113 {
114         // death etc.
115         if(e.anim_state & ANIMSTATE_FROZEN)
116                 return vec3(e.anim_idle.x, e.anim_time, ANIMPRIO_DEAD);
117         if(e.anim_state & ANIMSTATE_DEAD1)
118                 return vec3(e.anim_die1_x, e.anim_time, ANIMPRIO_DEAD);
119         if(e.anim_state & ANIMSTATE_DEAD2)
120                 return vec3(e.anim_die2_x, e.anim_time, ANIMPRIO_DEAD);
121
122         // is there an action?
123         vector outframe = '-1 0 0';
124         float t, a;
125         if(e.anim_upper_time >= e.anim_upper_implicit_time)
126         {
127                 a = e.anim_upper_action;
128                 t = e.anim_upper_time;
129         }
130         else
131         {
132                 a = e.anim_upper_implicit_action;
133                 t = e.anim_upper_implicit_time;
134         }
135         switch(a)
136         {
137                 case ANIMACTION_DRAW: outframe = e.anim_draw; break;
138                 case ANIMACTION_PAIN1: outframe = e.anim_pain1; break;
139                 case ANIMACTION_PAIN2: outframe = e.anim_pain2; break;
140                 case ANIMACTION_SHOOT: outframe = e.anim_shoot; break;
141                 case ANIMACTION_TAUNT: outframe = e.anim_taunt; break;
142                 case ANIMACTION_MELEE: outframe = e.anim_melee; break;
143         }
144         if(outframe.x >= 0)
145         {
146                 if(time <= t + outframe.y / outframe.z)
147                 {
148                         // animation is running!
149                         return vec3(outframe.x, t, ANIMPRIO_ACTIVE);
150                 }
151         }
152         // or, decide the anim by state
153         t = max(e.anim_time, e.anim_implicit_time);
154         // but all states are for lower body!
155         return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE);
156 }
157
158 vector animdecide_getloweranim(entity e)
159 {
160         // death etc.
161         if(e.anim_state & ANIMSTATE_FOLLOW)
162                 return vec3(((e.anim_state & ANIMSTATE_DUCK) ? e.anim_duckidle_x : e.anim_idle_x), e.anim_time, ANIMPRIO_DEAD); // dead priority so it's above all
163         if(e.anim_state & ANIMSTATE_FROZEN)
164                 return vec3(e.anim_idle.x, e.anim_time, ANIMPRIO_DEAD);
165         if(e.anim_state & ANIMSTATE_DEAD1)
166                 return vec3(e.anim_die1_x, e.anim_time, ANIMPRIO_DEAD);
167         if(e.anim_state & ANIMSTATE_DEAD2)
168                 return vec3(e.anim_die2_x, e.anim_time, ANIMPRIO_DEAD);
169
170         // is there an action?
171         vector outframe = '-1 0 0';
172         float t, a;
173         if(e.anim_lower_time >= e.anim_lower_implicit_time)
174         {
175                 a = e.anim_lower_action;
176                 t = e.anim_lower_time;
177         }
178         else
179         {
180                 a = e.anim_lower_implicit_action;
181                 t = e.anim_lower_implicit_time;
182         }
183         switch(a)
184         {
185                 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;
186         }
187         if(outframe.x >= 0)
188         {
189                 if(time <= t + outframe.y / outframe.z)
190                 {
191                         // animation is running!
192                         return vec3(outframe.x, t, ANIMPRIO_ACTIVE);
193                 }
194         }
195         // or, decide the anim by state
196         t = max(e.anim_time, e.anim_implicit_time);
197         if(e.anim_state & ANIMSTATE_DUCK)
198         {
199                 if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR)
200                         return vec3(e.anim_duckjump.x, 0, ANIMPRIO_CROUCH); // play the END of the jump anim
201                 else switch(e.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT))
202                 {
203                         case ANIMIMPLICITSTATE_FORWARD:
204                                 return vec3(e.anim_duckwalk.x, t, ANIMPRIO_CROUCH);
205                         case ANIMIMPLICITSTATE_BACKWARDS:
206                                 return vec3(e.anim_duckwalkbackwards.x, t, ANIMPRIO_CROUCH);
207                         case ANIMIMPLICITSTATE_RIGHT:
208                                 return vec3(e.anim_duckwalkstraferight.x, t, ANIMPRIO_CROUCH);
209                         case ANIMIMPLICITSTATE_LEFT:
210                                 return vec3(e.anim_duckwalkstrafeleft.x, t, ANIMPRIO_CROUCH);
211                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT:
212                                 return vec3(e.anim_duckwalkforwardright.x, t, ANIMPRIO_CROUCH);
213                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT:
214                                 return vec3(e.anim_duckwalkforwardleft.x, t, ANIMPRIO_CROUCH);
215                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT:
216                                 return vec3(e.anim_duckwalkbackright.x, t, ANIMPRIO_CROUCH);
217                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT:
218                                 return vec3(e.anim_duckwalkbackleft.x, t, ANIMPRIO_CROUCH);
219                         default:
220                                 return vec3(e.anim_duckidle.x, t, ANIMPRIO_CROUCH);
221                 }
222         }
223         else
224         {
225                 if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR)
226                         return vec3(e.anim_jump.x, 0, ANIMPRIO_ACTIVE); // play the END of the jump anim
227                 else switch(e.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT))
228                 {
229                         case ANIMIMPLICITSTATE_FORWARD:
230                                 return vec3(e.anim_run.x, t, ANIMPRIO_ACTIVE);
231                         case ANIMIMPLICITSTATE_BACKWARDS:
232                                 return vec3(e.anim_runbackwards.x, t, ANIMPRIO_ACTIVE);
233                         case ANIMIMPLICITSTATE_RIGHT:
234                                 return vec3(e.anim_straferight.x, t, ANIMPRIO_ACTIVE);
235                         case ANIMIMPLICITSTATE_LEFT:
236                                 return vec3(e.anim_strafeleft.x, t, ANIMPRIO_ACTIVE);
237                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT:
238                                 return vec3(e.anim_forwardright.x, t, ANIMPRIO_ACTIVE);
239                         case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT:
240                                 return vec3(e.anim_forwardleft.x, t, ANIMPRIO_ACTIVE);
241                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT:
242                                 return vec3(e.anim_backright.x, t, ANIMPRIO_ACTIVE);
243                         case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT:
244                                 return vec3(e.anim_backleft.x, t, ANIMPRIO_ACTIVE);
245                         default:
246                                 return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE);
247                 }
248         }
249         // can't get here
250         return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE);
251 }
252
253 void animdecide_setimplicitstate(entity e, float onground)
254 {
255         int s = 0;
256
257         makevectors(e.angles);
258         vector v;
259         v.x = e.velocity * v_forward;
260         v.y = e.velocity * v_right;
261         v.z = 0;
262
263         // we want to match like this:
264         // the 8 directions shall be "evenly spaced"
265         // that means, the forward key includes anything from -67.5 to +67.5 degrees
266         // which then means x > |y| * cot(3pi/8)
267         //
268         // BUT, the engine's clip-movement-to-keyboard function uses 0.5 here,
269         // which would be an angle range from -63.43 to +63.43 degrees, making
270         // it slightly less likely to "hit two keys at once", so let's do this
271         // here too
272
273         if(vlen(v) > 10)
274         {
275                 if(v.x >  fabs(v.y) * 0.5)
276                         s |= ANIMIMPLICITSTATE_FORWARD;
277                 if(v.x < -fabs(v.y) * 0.5)
278                         s |= ANIMIMPLICITSTATE_BACKWARDS;
279                 if(v.y >  fabs(v.x) * 0.5)
280                         s |= ANIMIMPLICITSTATE_RIGHT;
281                 if(v.y < -fabs(v.x) * 0.5)
282                         s |= ANIMIMPLICITSTATE_LEFT;
283         }
284         if(!onground)
285                 s |= ANIMIMPLICITSTATE_INAIR;
286
287         // detect some kinds of otherwise misdetected jumps (ground to air transition)
288         // NOTE: currently, in CSQC this is the only jump detection, as the explicit jump action is never called!
289         if(!(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR) && (s & ANIMIMPLICITSTATE_INAIR))
290         {
291                 e.anim_lower_implicit_action = ANIMACTION_JUMP;
292                 e.anim_lower_implicit_time = time;
293         }
294
295         if(s != e.anim_implicit_state)
296         {
297                 e.anim_implicit_state = s;
298                 e.anim_implicit_time = time;
299         }
300 }
301 void animdecide_setframes(entity e, float support_blending, .float fld_frame, .float fld_frame1time, .float fld_frame2, .float fld_frame2time)
302 {
303         // _x: frame
304         // _y: start time
305         // _z: priority
306         vector upper = animdecide_getupperanim(e);
307         vector lower = animdecide_getloweranim(e);
308         //print("UPPER: ", vtos(upper), ", LOWER: ", vtos(lower), "\n");
309         if(support_blending)
310         {
311                 if(upper.z && !lower.z)
312                         lower = upper;
313                 else if(lower.z && !upper.z)
314                         upper = lower;
315                 if(e.frame1time != upper.y || e.frame2time != lower.y)
316                         BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
317                 e.(fld_frame) = upper.x;
318                 e.(fld_frame1time) = upper.y;
319                 e.(fld_frame2) = lower.x;
320                 e.(fld_frame2time) = lower.y;
321         }
322         else
323         {
324                 if(upper.z > lower.z)
325                         lower = upper;
326                 else if(lower.z > upper.z)
327                         upper = lower;
328                 if(e.frame1time != upper.y)
329                         BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
330                 e.(fld_frame) = upper.x;
331                 e.(fld_frame1time) = upper.y;
332         }
333 }
334
335 void animdecide_setstate(entity e, int newstate, float restart)
336 {
337         if(!restart)
338                 if(newstate == e.anim_state)
339                         return;
340         e.anim_state = newstate;
341         e.anim_time = time;
342 }
343 void animdecide_setaction(entity e, float action, float restart)
344 {
345         if(action < 0)
346         {
347                 if(!restart)
348                         if(action == e.anim_lower_action)
349                                 return;
350                 e.anim_lower_action = action;
351                 e.anim_lower_time = time;
352         }
353         else
354         {
355                 if(!restart)
356                         if(action == e.anim_upper_action)
357                                 return;
358                 e.anim_upper_action = action;
359                 e.anim_upper_time = time;
360         }
361 }