]> git.jsancho.org Git - lugaru.git/blob - Source/Person.cpp
Cleaned up a bit clothes adding
[lugaru.git] / Source / Person.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /**> HEADER FILES <**/
22 #include "Person.h"
23 #include "openal_wrapper.h"
24 #include "Animation.h"
25 #include "Sounds.h"
26 #include "Awards.h"
27 #include "Game.h"
28
29 extern float multiplier;
30 extern Terrain terrain;
31 extern float gravity;
32 extern int environment;
33 extern int detail;
34 extern FRUSTUM frustum;
35 extern XYZ viewer;
36 extern float realmultiplier;
37 extern int slomo;
38 extern float slomodelay;
39 extern bool cellophane;
40 extern float texdetail;
41 extern float realtexdetail;
42 extern GLubyte bloodText[512 * 512 * 3];
43 extern GLubyte wolfbloodText[512 * 512 * 3];
44 extern int bloodtoggle;
45 extern Objects objects;
46 extern bool autoslomo;
47 extern float camerashake;
48 extern float woozy;
49 extern float viewdistance;
50 extern float blackout;
51 extern int difficulty;
52 extern bool decals;
53 extern float fadestart;
54 extern bool freeze;
55 extern bool winfreeze;
56 extern float flashamount, flashr, flashg, flashb;
57 extern int flashdelay;
58 extern bool showpoints;
59 extern bool immediate;
60 extern int test;
61 extern bool tilt2weird;
62 extern bool tiltweird;
63 extern bool midweird;
64 extern bool proportionweird;
65 extern bool vertexweird[6];
66 extern XYZ envsound[30];
67 extern float envsoundvol[30];
68 extern float envsoundlife[30];
69 extern int numenvsounds;
70 extern int tutoriallevel;
71 extern float smoketex;
72 extern int tutorialstage;
73 extern bool reversaltrain;
74 extern bool canattack;
75 extern bool cananger;
76 extern float damagedealt;
77 extern int hostile;
78 extern float hostiletime;
79
80 extern int indialogue;
81
82 extern bool gamestarted;
83
84 std::vector<std::shared_ptr<Person>> Person::players(1, std::shared_ptr<Person>(new Person()));
85
86 /* EFFECT
87  *
88  * USES:
89  * GameTick/doPlayerCollisions
90  */
91 void Person::CheckKick()
92 {
93     if (!(hasvictim
94             && (animTarget == rabbitkickanim
95                 && victim
96                 && victim != this->shared_from_this()
97                 && frameCurrent >= 2
98                 && animCurrent == rabbitkickanim)
99             && distsq(&coords, &victim->coords) < 1.2
100             && !victim->skeleton.free))
101         return;
102
103     if (animation[victim->animTarget].height != lowheight) {
104         float damagemult = (creature == wolftype ? 2.5 : 1.) * power * power;
105         XYZ relative = velocity;
106         relative.y = 0;
107         Normalise(&relative);
108
109         victim->spurt = 1;
110         DoBlood(.2, 250);
111         if (tutoriallevel != 1)
112             emit_sound_at(heavyimpactsound, victim->coords);
113         victim->RagDoll(0);
114         for (int i = 0; i < victim->skeleton.num_joints; i++) {
115             victim->skeleton.joints[i].velocity += relative * 120 * damagemult;
116         }
117         victim->Puff(neck);
118         victim->DoDamage(100 * damagemult / victim->protectionhigh);
119         if (id == 0)
120             camerashake += .4;
121
122         target = 0;
123         frameCurrent = 3;
124         animTarget = backflipanim;
125         frameTarget = 4;
126         velocity = facing * -10;
127         velocity.y = 5;
128         skeleton.free = 0;
129         if (id == 0)
130             resume_stream(whooshsound);
131
132         award_bonus(id, cannon);
133     } else if (victim->isCrouch()) {
134         animTarget = rabbitkickreversedanim;
135         animCurrent = rabbitkickreversedanim;
136         victim->animCurrent = rabbitkickreversalanim;
137         victim->animTarget = rabbitkickreversalanim;
138         targettilt2 = 0;
139         frameCurrent = 0;
140         frameTarget = 1;
141         target = 0;
142         velocity = 0;
143         victim->oldcoords = victim->coords;
144         coords = victim->coords;
145         victim->targetyaw = targetyaw;
146         victim->victim = this->shared_from_this();
147     }
148 }
149
150 /* EFFECT
151  *
152  * USES:
153  * GameTick/doPlayerCollisions - spread fire between players
154  * GameTick/doDebugKeys - press f to ignite
155  * Person::DoStuff - spread fire from lit campfires and bushes
156  */
157 void Person::CatchFire()
158 {
159     XYZ flatfacing, flatvelocity;
160     int howmany;
161     for (int i = 0; i < 10; i++) {
162         howmany = abs(Random() % (skeleton.num_joints));
163         if (skeleton.free) {
164             flatvelocity = skeleton.joints[howmany].velocity;
165             flatfacing = skeleton.joints[howmany].position * scale + coords;
166         } else {
167             flatvelocity = velocity;
168             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
169         }
170         Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, 2, 1);
171     }
172
173     onfiredelay = 0.5;
174
175     emit_sound_at(firestartsound, coords);
176
177     emit_stream_at(stream_firesound, coords);
178
179     flamedelay = 0;
180
181     onfire = 1;
182 }
183
184 /* FUNCTION
185  * idle animation for this creature (depending on status)
186  */
187 int Person::getIdle()
188 {
189     if (indialogue != -1 && howactive == typeactive && creature == rabbittype)
190         return talkidleanim;
191     if (hasvictim && (victim != this->shared_from_this())/*||(id==0&&attackkeydown)*/)
192         if (/*(id==0&&attackkeydown)||*/(!victim->dead && victim->aitype != passivetype &&
193             victim->aitype != searchtype && aitype != passivetype && aitype != searchtype &&
194             victim->id < Person::players.size())) {
195             if ((aitype == playercontrolled && stunned <= 0 && weaponactive == -1) || pause) {
196                 if (creature == rabbittype)
197                     return fightidleanim;
198                 if (creature == wolftype)
199                     return wolfidle;
200             }
201             if (aitype == playercontrolled && stunned <= 0 && weaponactive != -1) {
202                 if (weapons[weaponids[weaponactive]].getType() == knife)
203                     return knifefightidleanim;
204                 if (weapons[weaponids[weaponactive]].getType() == sword && victim->weaponactive != -1)
205                     return swordfightidlebothanim;
206                 if (weapons[weaponids[weaponactive]].getType() == sword)
207                     return swordfightidleanim;
208                 if (weapons[weaponids[weaponactive]].getType() == staff)
209                     return swordfightidleanim;
210             }
211             if (aitype != playercontrolled && stunned <= 0 && creature != wolftype && !pause)
212                 return fightsidestep;
213         }
214     if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && creature != wolftype)
215         return hurtidleanim;
216     if (howactive == typesitting) return sitanim;
217     if (howactive == typesittingwall) return sitwallanim;
218     if (howactive == typesleeping) return sleepanim;
219     if (howactive == typedead1) return dead1anim;
220     if (howactive == typedead2) return dead2anim;
221     if (howactive == typedead3) return dead3anim;
222     if (howactive == typedead4) return dead4anim;
223     if (creature == rabbittype) return bounceidleanim;
224     if (creature == wolftype) return wolfidle;
225     return 0;
226 }
227
228 /* FUNCTION
229  * crouch animation for this creature
230  */
231 int Person::getCrouch()
232 {
233     if (creature == rabbittype)
234         return crouchanim;
235     if (creature == wolftype)
236         return wolfcrouchanim;
237     return 0;
238 }
239
240 /* FUNCTION
241  * running animation for this creature (can be upright or all fours)
242  */
243 int Person::getRun()
244 {
245     if (creature == rabbittype && (!superruntoggle || weaponactive != -1))
246         return runanim;
247     if (creature == wolftype && (!superruntoggle))
248         return wolfrunanim;
249
250     if (creature == rabbittype && (superruntoggle && weaponactive == -1))
251         return rabbitrunninganim;
252     if (creature == wolftype && (superruntoggle))
253         return wolfrunninganim;
254     return 0;
255 }
256
257 /* FUNCTION
258  */
259 int Person::getStop()
260 {
261     if (creature == rabbittype)
262         return stopanim;
263     if (creature == wolftype)
264         return wolfstopanim;
265     return 0;
266 }
267
268 /* FUNCTION
269  */
270 int Person::getLanding()
271 {
272     if (creature == rabbittype)
273         return landanim;
274     if (creature == wolftype)
275         return wolflandanim;
276     return 0;
277 }
278
279 /* FUNCTION
280  */
281 int Person::getLandhard()
282 {
283     if (creature == rabbittype)
284         return landhardanim;
285     if (creature == wolftype)
286         return wolflandhardanim;
287     return 0;
288 }
289
290 /* EFFECT
291  *
292  * USES:
293  * Person::DoAnimations
294  */
295 static void
296 SolidHitBonus(int playerid)
297 {
298     if (bonustime < 1.5 && bonus >= solidhit && bonus <= megacombo)
299         award_bonus(playerid, bonus == megacombo ? bonus : bonus + 1);
300     else
301         award_bonus(playerid, solidhit);
302 }
303
304 /* EFFECT
305  * spawns blood effects
306  */
307 void Person::DoBlood(float howmuch, int which)
308 {
309     // FIXME: should abstract out inputs
310     static int bleedxint, bleedyint;
311     static XYZ bloodvel;
312     if (bloodtoggle && tutoriallevel != 1) {
313         if (bleeding <= 0 && spurt) {
314             spurt = 0;
315             for (int i = 0; i < 3; i++) {
316                 // emit blood particles
317                 bloodvel = 0;
318                 if (skeleton.free) {
319                     bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
320                     bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
321                     Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
322                     Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
323                 } else {
324                     bloodvel.z = 10;
325                     bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
326                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
327                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
328                     Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
329                 }
330             }
331             if (Random() % 2 == 0) // 50% chance
332                 for (int i = 0; i < 3; i++) {
333                     if (Random() % 2 != 0) {
334                         // emit teeth particles
335                         bloodvel = 0;
336                         if (skeleton.free) {
337                             bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
338                             bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
339                         } else {
340                             bloodvel.z = 10;
341                             bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
342                             bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
343                         }
344                         bloodvel *= .2;
345                         if (skeleton.free) {
346                             Sprite::MakeSprite(splintersprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
347                         } else {
348                             Sprite::MakeSprite(splintersprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
349                         }
350                         Sprite::setLastSpriteSpecial(3); // sets it to teeth
351                     }
352                 }
353         }
354         if (decals) {
355             // FIXME: manipulating attributes
356             bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
357             bleedxint = 0;
358             bleedyint = 0;
359             if (creature == rabbittype)
360                 while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
361                     bleedxint = abs(Random() % 512);
362                     bleedyint = abs(Random() % 512);
363                 }
364             if (creature == wolftype)
365                 while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
366                     bleedxint = abs(Random() % 512);
367                     bleedyint = abs(Random() % 512);
368                 }
369             bleedy = bleedxint;
370             bleedx = bleedyint;
371             bleedy /= realtexdetail;
372             bleedx /= realtexdetail;
373             direction = abs(Random() % 2) * 2 - 1;
374         }
375
376     }
377     if (bleeding > 2)
378         bleeding = 2;
379 }
380
381 /* EFFECT
382  * spawns big blood effects and ???
383  * modifies character's skin texture
384  */
385 void Person::DoBloodBig(float howmuch, int which)
386 {
387     static int bleedxint, bleedyint, i, j;
388     static XYZ bloodvel;
389     if (howmuch && id == 0)
390         blooddimamount = 1;
391
392     if (tutoriallevel != 1 || id == 0)
393         if (aitype != playercontrolled && howmuch > 0) {
394             // play pain sounds
395             int whichsound = -1;
396
397             // FIXME: seems to be spawning sounds by manipulating attributes... MESSY!
398             if (creature == wolftype) {
399                 int i = abs(Random() % 2);
400                 if (i == 0)
401                     whichsound = snarlsound;
402                 if (i == 1)
403                     whichsound = snarl2sound;
404                 envsound[numenvsounds] = coords;
405                 envsoundvol[numenvsounds] = 16;
406                 envsoundlife[numenvsounds] = .4;
407                 numenvsounds++;
408             }
409             if (creature == rabbittype) {
410                 int i = abs(Random() % 2);
411                 if (i == 0)
412                     whichsound = rabbitpainsound;
413                 if (i == 1 && howmuch >= 2)
414                     whichsound = rabbitpain1sound;
415                 envsound[numenvsounds] = coords;
416                 envsoundvol[numenvsounds] = 16;
417                 envsoundlife[numenvsounds] = .4;
418                 numenvsounds++;
419             }
420
421             if (whichsound != -1)
422                 emit_sound_at(whichsound, coords);
423         }
424
425     if (id == 0 && howmuch > 0) {
426         // FIXME: manipulating attributes
427         flashamount = .5;
428         flashr = 1;
429         flashg = 0;
430         flashb = 0;
431         flashdelay = 0;
432     }
433
434     if (bloodtoggle && decals && tutoriallevel != 1) {
435         if (bleeding <= 0 && spurt) {
436             spurt = 0;
437             for (int i = 0; i < 3; i++) {
438                 // emit blood particles
439                 // FIXME: copypaste from above
440                 bloodvel = 0;
441                 if (skeleton.free) {
442                     bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
443                     bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
444                     Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
445                     Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
446                 } else {
447                     bloodvel.z = 10;
448                     bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
449                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
450                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
451                     Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
452                 }
453             }
454         }
455
456         // weird texture manipulation code follows.
457         // looks like this is painting blood onto the character's skin texture
458         // FIXME: surely there's a better way
459
460         int offsetx = 0, offsety = 0;
461         if (which == 225) {
462             offsety = Random() % 40;
463             offsetx = abs(Random() % 60);
464         }
465         if (which == 190 || which == 185) {
466             offsety = Random() % 40;
467             offsetx = abs(Random() % 100) - 20;
468         }
469         if (which == 175) {
470             offsety = Random() % 10;
471             offsetx = Random() % 10;
472         }
473         if (which == 170) {
474             offsety = Random() % 20;
475             offsetx = Random() % 20;
476         }
477         if (which == 220 || which == 215) {
478             offsetx = 20;
479         }
480
481
482         int startx = 512;
483         int starty = 512;
484         int endx = 0;
485         int endy = 0;
486         GLubyte color;
487         if (creature == rabbittype)
488             for (i = 0; i < 512; i++) {
489                 for (j = 0; j < 512; j++) {
490                     if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
491                         if (i < startx) startx = i;
492                         if (j < starty) starty = j;
493                         if (i > endx) endx = i;
494                         if (j > endy) endy = j;
495                     }
496                 }
497             }
498         if (creature == wolftype)
499             for (i = 0; i < 512; i++) {
500                 for (j = 0; j < 512; j++) {
501                     if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
502                         if (i < startx) startx = i;
503                         if (j < starty) starty = j;
504                         if (i > endx) endx = i;
505                         if (j > endy) endy = j;
506                     }
507                 }
508             }
509
510         startx += offsetx;
511         endx += offsetx;
512         starty += offsety;
513         endy += offsety;
514
515         if (startx < 0) startx = 0;
516         if (starty < 0) starty = 0;
517         if (endx > 512 - 1) endx = 512 - 1;
518         if (endy > 512 - 1) endy = 512 - 1;
519         if (endx < startx) endx = startx;
520         if (endy < starty) endy = starty;
521
522         startx /= realtexdetail;
523         starty /= realtexdetail;
524         endx /= realtexdetail;
525         endy /= realtexdetail;
526
527         int texdetailint = realtexdetail;
528         int where;
529         if (creature == rabbittype)
530             for (i = startx; i < endx; i++) {
531                 for (j = starty; j < endy; j++) {
532                     if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
533                         color = Random() % 85 + 170;
534                         where = i * skeleton.skinsize * 3 + j * 3;
535                         if (skeleton.skinText[where + 0] > color / 2)
536                             skeleton.skinText[where + 0] = color / 2;
537                         skeleton.skinText[where + 1] = 0;
538                         skeleton.skinText[where + 2] = 0;
539                     }
540                 }
541             }
542         if (creature == wolftype)
543             for (i = startx; i < endx; i++) {
544                 for (j = starty; j < endy; j++) {
545                     if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
546                         color = Random() % 85 + 170;
547                         where = i * skeleton.skinsize * 3 + j * 3;
548                         if (skeleton.skinText[where + 0] > color / 2)
549                             skeleton.skinText[where + 0] = color / 2;
550                         skeleton.skinText[where + 1] = 0;
551                         skeleton.skinText[where + 2] = 0;
552                     }
553                 }
554             }
555         skeleton.drawmodel.textureptr.bind();
556         DoMipmaps();
557
558         bleedxint = 0;
559         bleedyint = 0;
560         if (creature == rabbittype)
561             while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
562                 bleedxint = abs(Random() % 512);
563                 bleedyint = abs(Random() % 512);
564             }
565         if (creature == wolftype)
566             while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
567                 bleedxint = abs(Random() % 512);
568                 bleedyint = abs(Random() % 512);
569             }
570         bleedy = bleedxint + offsetx;
571         bleedx = bleedyint + offsety;
572         bleedy /= realtexdetail;
573         bleedx /= realtexdetail;
574         if (bleedx < 0)
575             bleedx = 0;
576         if (bleedy < 0)
577             bleedy = 0;
578         if (bleedx > skeleton.skinsize - 1)
579             bleedx = skeleton.skinsize - 1;
580         if (bleedy > skeleton.skinsize - 1)
581             bleedy = skeleton.skinsize - 1;
582         direction = abs(Random() % 2) * 2 - 1;
583
584     }
585     bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
586     deathbleeding += bleeding;
587     bloodloss += bleeding * 3;
588
589     if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
590         if (abs(Random() % 2) == 0) {
591             aitype = gethelptype;
592             lastseentime = 12;
593         } else
594             aitype = attacktypecutoff;
595         ally = 0;
596     }
597     if (bleeding > 2)
598         bleeding = 2;
599 }
600
601 /* EFFECT
602  * similar to DoBloodBig
603  */
604 bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
605 {
606     static int i, j;
607     static XYZ bloodvel;
608     static XYZ startpoint, endpoint, colpoint, movepoint;
609     static float rotationpoint;
610     static int whichtri;
611     static XYZ p1, p2, p3, p0;
612     XYZ bary;
613     XYZ gxx, gyy;
614     float coordsx, coordsy;
615     float total;
616
617     if (bloodtoggle && decals && tutoriallevel != 1) {
618         where -= coords;
619         if (!skeleton.free)
620             where = DoRotation(where, 0, -yaw, 0);
621         //where=scale;
622         startpoint = where;
623         startpoint.y += 100;
624         endpoint = where;
625         endpoint.y -= 100;
626         movepoint = 0;
627         rotationpoint = 0;
628         // ray testing for a tri in the character model
629         whichtri = skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
630         if (whichtri != -1) {
631             // low level geometry math
632             p0 = colpoint;
633             p1 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[0]];
634             p2 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[1]];
635             p3 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[2]];
636
637             bary.x = distsq(&p0, &p1);
638             bary.y = distsq(&p0, &p2);
639             bary.z = distsq(&p0, &p3);
640
641             total = bary.x + bary.y + bary.z;
642             bary.x /= total;
643             bary.y /= total;
644             bary.z /= total;
645
646             bary.x = 1 - bary.x;
647             bary.y = 1 - bary.y;
648             bary.z = 1 - bary.z;
649
650             total = bary.x + bary.y + bary.z;
651             bary.x /= total;
652             bary.y /= total;
653             bary.z /= total;
654
655
656             gxx.x = skeleton.drawmodel.Triangles[whichtri].gx[0];
657             gxx.y = skeleton.drawmodel.Triangles[whichtri].gx[1];
658             gxx.z = skeleton.drawmodel.Triangles[whichtri].gx[2];
659             gyy.x = skeleton.drawmodel.Triangles[whichtri].gy[0];
660             gyy.y = skeleton.drawmodel.Triangles[whichtri].gy[1];
661             gyy.z = skeleton.drawmodel.Triangles[whichtri].gy[2];
662             coordsx = skeleton.drawmodel.Triangles[whichtri].gx[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gx[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gx[2] * bary.z;
663             coordsy = skeleton.drawmodel.Triangles[whichtri].gy[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gy[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gy[2] * bary.z;
664
665             if (bleeding <= 0 && spurt) {
666                 spurt = 0;
667                 for (int i = 0; i < 3; i++) {
668                     // emit blood particles
669                     // FIXME: more copypaste code
670                     bloodvel = 0;
671                     if (skeleton.free) {
672                         bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
673                         bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
674                         Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
675                         Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
676                     } else {
677                         bloodvel.z = 10;
678                         bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
679                         bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
680                         Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
681                         Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
682                     }
683                 }
684             }
685
686             // texture manipulation follows
687
688             int offsetx = 0, offsety = 0;
689             offsetx = (1 + coordsy) * 512 - 291;
690             offsety = coordsx * 512 - 437;
691
692             int startx = 512;
693             int starty = 512;
694             int endx = 0;
695             int endy = 0;
696             GLubyte color;
697             if (creature == rabbittype)
698                 for (i = 0; i < 512; i++) {
699                     for (j = 0; j < 512; j++) {
700                         if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
701                             if (i < startx) startx = i;
702                             if (j < starty) starty = j;
703                             if (i > endx) endx = i;
704                             if (j > endy) endy = j;
705                         }
706                     }
707                 }
708             if (creature == wolftype)
709                 for (i = 0; i < 512; i++) {
710                     for (j = 0; j < 512; j++) {
711                         if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
712                             if (i < startx) startx = i;
713                             if (j < starty) starty = j;
714                             if (i > endx) endx = i;
715                             if (j > endy) endy = j;
716                         }
717                     }
718                 }
719             startx += offsetx;
720             endx += offsetx;
721             starty += offsety;
722             endy += offsety;
723
724             if (startx < 0) startx = 0;
725             if (starty < 0) starty = 0;
726             if (endx > 512 - 1) endx = 512 - 1;
727             if (endy > 512 - 1) endy = 512 - 1;
728             if (endx < startx) endx = startx;
729             if (endy < starty) endy = starty;
730
731             startx /= realtexdetail;
732             starty /= realtexdetail;
733             endx /= realtexdetail;
734             endy /= realtexdetail;
735
736             int texdetailint = realtexdetail;
737             int where;
738             if (creature == rabbittype)
739                 for (i = startx; i < endx; i++) {
740                     for (j = starty; j < endy; j++) {
741                         if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
742                             color = Random() % 85 + 170;
743                             where = i * skeleton.skinsize * 3 + j * 3;
744                             if (skeleton.skinText[where + 0] > color / 2)
745                                 skeleton.skinText[where + 0] = color / 2;
746                             skeleton.skinText[where + 1] = 0;
747                             skeleton.skinText[where + 2] = 0;
748                         } else if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
749                             color = Random() % 85 + 170;
750                             where = i * skeleton.skinsize * 3 + j * 3;
751                             if (skeleton.skinText[where + 0] > color / 2)
752                                 skeleton.skinText[where + 0] = color / 2;
753                             skeleton.skinText[where + 1] = 0;
754                             skeleton.skinText[where + 2] = 0;
755                         }
756                     }
757                 }
758             if (creature == wolftype)
759                 for (i = startx; i < endx; i++) {
760                     for (j = starty; j < endy; j++) {
761                         if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
762                             color = Random() % 85 + 170;
763                             where = i * skeleton.skinsize * 3 + j * 3;
764                             if (skeleton.skinText[where + 0] > color / 2)
765                                 skeleton.skinText[where + 0] = color / 2;
766                             skeleton.skinText[where + 1] = 0;
767                             skeleton.skinText[where + 2] = 0;
768                         } else if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
769                             color = Random() % 85 + 170;
770                             where = i * skeleton.skinsize * 3 + j * 3;
771                             if (skeleton.skinText[where + 0] > color / 2)
772                                 skeleton.skinText[where + 0] = color / 2;
773                             skeleton.skinText[where + 1] = 0;
774                             skeleton.skinText[where + 2] = 0;
775                         }
776                     }
777                 }
778             skeleton.drawmodel.textureptr.bind();
779             DoMipmaps();
780
781             bleedy = (1 + coordsy) * 512;
782             bleedx = coordsx * 512;
783             bleedy /= realtexdetail;
784             bleedx /= realtexdetail;
785             if (bleedx < 0)
786                 bleedx = 0;
787             if (bleedy < 0)
788                 bleedy = 0;
789             if (bleedx > skeleton.skinsize - 1)
790                 bleedx = skeleton.skinsize - 1;
791             if (bleedy > skeleton.skinsize - 1)
792                 bleedy = skeleton.skinsize - 1;
793             direction = abs(Random() % 2) * 2 - 1;
794         }
795         if (whichtri == -1)
796             return 0;
797     }
798     bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
799     deathbleeding += bleeding;
800     bloodloss += bleeding * 3;
801
802     if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
803         if (abs(Random() % 2) == 0) {
804             aitype = gethelptype;
805             lastseentime = 12;
806         } else
807             aitype = attacktypecutoff;
808         ally = 0;
809     }
810     if (bleeding > 2)
811         bleeding = 2;
812     return 1;
813 }
814
815
816
817 /* EFFECT
818  * guessing this performs a reversal
819  */
820 void Person::Reverse()
821 {
822     if (!((victim->aitype == playercontrolled
823             || hostiletime > 1
824             || staggerdelay <= 0)
825             && victim->animTarget != jumpupanim
826             && victim->animTarget != jumpdownanim
827             && (tutoriallevel != 1 || cananger)
828             && hostile))
829         return;
830
831     if (normaldotproduct (victim->facing, victim->coords - coords) > 0
832             && (victim->id != 0 || difficulty >= 2)
833             && (creature != wolftype || victim->creature == wolftype))
834         return;
835
836     if (animTarget == sweepanim) {
837         animTarget = sweepreversedanim;
838         animCurrent = sweepreversedanim;
839         victim->animCurrent = sweepreversalanim;
840         victim->animTarget = sweepreversalanim;
841     }
842     if (animTarget == spinkickanim) {
843         animTarget = spinkickreversedanim;
844         animCurrent = spinkickreversedanim;
845         victim->animCurrent = spinkickreversalanim;
846         victim->animTarget = spinkickreversalanim;
847     }
848     if (animTarget == upunchanim || animTarget == rabbittacklinganim) {
849         if (animTarget == rabbittacklinganim) {
850             frameCurrent = 6;
851             frameTarget = 7;
852             victim->frameCurrent = 6;
853             victim->frameTarget = 7;
854         }
855         animTarget = upunchreversedanim;
856         animCurrent = upunchreversedanim;
857         victim->animCurrent = upunchreversalanim;
858         victim->animTarget = upunchreversalanim;
859     }
860     if (animTarget == staffhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
861         if (victim->weaponactive != -1) {
862             victim->throwtogglekeydown = 1;
863             XYZ tempVelocity = victim->velocity * .2;
864             if (tempVelocity.x == 0)
865                 tempVelocity.x = .1;
866             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
867             victim->num_weapons--;
868             if (victim->num_weapons) {
869                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
870                 if (victim->weaponstuck == victim->num_weapons)
871                     victim->weaponstuck = 0;
872             }
873
874             victim->weaponactive = -1;
875             for (unsigned j = 0; j < Person::players.size(); j++) {
876                 Person::players[j]->wentforweapon = 0;
877             }
878         }
879
880         animTarget = staffhitreversedanim;
881         animCurrent = staffhitreversedanim;
882         victim->animCurrent = staffhitreversalanim;
883         victim->animTarget = staffhitreversalanim;
884     }
885     if (animTarget == staffspinhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 2 == 0)) {
886         if (victim->weaponactive != -1) {
887             victim->throwtogglekeydown = 1;
888             XYZ tempVelocity = victim->velocity * .2;
889             if (tempVelocity.x == 0)
890                 tempVelocity.x = .1;
891             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
892             victim->num_weapons--;
893             if (victim->num_weapons) {
894                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
895                 if (victim->weaponstuck == victim->num_weapons)
896                     victim->weaponstuck = 0;
897             }
898
899             victim->weaponactive = -1;
900             for (unsigned j = 0; j < Person::players.size(); j++) {
901                 Person::players[j]->wentforweapon = 0;
902             }
903         }
904         animTarget = staffspinhitreversedanim;
905         animCurrent = staffspinhitreversedanim;
906         victim->animCurrent = staffspinhitreversalanim;
907         victim->animTarget = staffspinhitreversalanim;
908     }
909     if (animTarget == swordslashanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
910         if (victim->weaponactive != -1) {
911             victim->throwtogglekeydown = 1;
912             XYZ tempVelocity = victim->velocity * .2;
913             if (tempVelocity.x == 0)
914                 tempVelocity.x = .1;
915             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
916             victim->num_weapons--;
917             if (victim->num_weapons) {
918                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
919                 if (victim->weaponstuck == victim->num_weapons)
920                     victim->weaponstuck = 0;
921             }
922
923             victim->weaponactive = -1;
924             for (unsigned j = 0; j < Person::players.size(); j++) {
925                 Person::players[j]->wentforweapon = 0;
926             }
927         }
928         animTarget = swordslashreversedanim;
929         animCurrent = swordslashreversedanim;
930         victim->animCurrent = swordslashreversalanim;
931         victim->animTarget = swordslashreversalanim;
932     }
933     if (animTarget == knifeslashstartanim && distsq(&victim->coords, &coords) < 2 && (victim->id == 0 || Random() % 4 == 0)) {
934         if (victim->weaponactive != -1) {
935             victim->throwtogglekeydown = 1;
936             XYZ tempVelocity = victim->velocity * .2;
937             if (tempVelocity.x == 0)
938                 tempVelocity.x = .1;
939             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
940             victim->num_weapons--;
941             if (victim->num_weapons) {
942                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
943                 if (victim->weaponstuck == victim->num_weapons)
944                     victim->weaponstuck = 0;
945             }
946
947             victim->weaponactive = -1;
948             for (unsigned j = 0; j < Person::players.size(); j++) {
949                 Person::players[j]->wentforweapon = 0;
950             }
951         }
952         animTarget = knifeslashreversedanim;
953         animCurrent = knifeslashreversedanim;
954         victim->animCurrent = knifeslashreversalanim;
955         victim->animTarget = knifeslashreversalanim;
956     }
957     if (animTarget != knifeslashstartanim && animTarget != staffhitanim && animTarget != staffspinhitanim && animTarget != winduppunchanim && animTarget != wolfslapanim && animTarget != swordslashanim) {
958         victim->targettilt2 = targettilt2;
959         victim->frameCurrent = frameCurrent;
960         victim->frameTarget = frameTarget;
961         victim->target = target;
962         victim->velocity = 0;
963         victim->oldcoords = victim->coords;
964         victim->coords = coords;
965         victim->targetyaw = targetyaw;
966         victim->yaw = targetyaw;
967         victim->victim = this->shared_from_this();
968     }
969     if (animTarget == winduppunchanim) {
970         animTarget = winduppunchblockedanim;
971         victim->animTarget = blockhighleftanim;
972         victim->frameTarget = 1;
973         victim->target = .5;
974         victim->victim = this->shared_from_this();
975         victim->targetyaw = targetyaw + 180;
976     }
977     if (animTarget == wolfslapanim) {
978         animTarget = winduppunchblockedanim;
979         victim->animTarget = blockhighleftanim;
980         victim->frameTarget = 1;
981         victim->target = .5;
982         victim->victim = this->shared_from_this();
983         victim->targetyaw = targetyaw + 180;
984     }
985     if ((animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) && victim->weaponactive != -1) {
986         animTarget = swordslashparriedanim;
987         parriedrecently = .4;
988         victim->parriedrecently = 0;
989         victim->animTarget = swordslashparryanim;
990         victim->frameTarget = 1;
991         victim->target = .5;
992         victim->victim = this->shared_from_this();
993         victim->targetyaw = targetyaw + 180;
994
995         if (abs(Random() % 20) == 0 || weapons[victim->weaponids[victim->weaponactive]].getType() == knife) {
996             if (victim->weaponactive != -1) {
997                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
998                     if (weapons[victim->weaponids[0]].getType() == staff)
999                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1000                     if (weapons[weaponids[0]].getType() == staff)
1001                         weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1002                     emit_sound_at(swordstaffsound, victim->coords);
1003                 } else {
1004                     emit_sound_at(metalhitsound, victim->coords);
1005                 }
1006             }
1007             XYZ aim;
1008             victim->Puff(righthand);
1009             victim->target = 0;
1010             victim->frameTarget = 0;
1011             victim->animTarget = staggerbackhighanim;
1012             victim->targetyaw = targetyaw + 180;
1013             victim->target = 0;
1014             aim = DoRotation(facing, 0, 90, 0) * 21;
1015             aim.y += 7;
1016             weapons[victim->weaponids[0]].drop(aim * -.2, aim);
1017             victim->num_weapons--;
1018             if (victim->num_weapons) {
1019                 victim->weaponids[0] = victim->weaponids[num_weapons];
1020                 if (victim->weaponstuck == victim->num_weapons)
1021                     victim->weaponstuck = 0;
1022             }
1023             victim->weaponactive = -1;
1024             for (unsigned i = 0; i < Person::players.size(); i++) {
1025                 Person::players[i]->wentforweapon = 0;
1026             }
1027         }
1028
1029         if (abs(Random() % 20) == 0) {
1030             if (weaponactive != -1) {
1031                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
1032                     if (weapons[victim->weaponids[0]].getType() == staff)
1033                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1034                     if (weapons[weaponids[0]].getType() == staff)
1035                         weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1036
1037                     emit_sound_at(swordstaffsound, coords);
1038                 } else {
1039                     emit_sound_at(metalhitsound, coords);
1040                 }
1041             }
1042
1043             XYZ aim;
1044             Puff(righthand);
1045             target = 0;
1046             frameTarget = 0;
1047             animTarget = staggerbackhighanim;
1048             targetyaw = targetyaw + 180;
1049             target = 0;
1050             aim = DoRotation(facing, 0, 90, 0) * 21;
1051             aim.y += 7;
1052             weapons[victim->weaponids[0]].drop(aim * -.2, aim);
1053             num_weapons--;
1054             if (num_weapons) {
1055                 weaponids[0] = weaponids[num_weapons];
1056                 if (weaponstuck == num_weapons)
1057                     weaponstuck = 0;
1058             }
1059             weaponactive = -1;
1060             for (unsigned i = 0; i < Person::players.size(); i++) {
1061                 Person::players[i]->wentforweapon = 0;
1062             }
1063
1064
1065         }
1066     }
1067     if (hasvictim)
1068         if (animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) {
1069             if ((animTarget != staffhitanim && animTarget != staffspinhitanim) || distsq(&coords, &victim->coords) > .2) {
1070                 victim->animTarget = dodgebackanim;
1071                 victim->frameTarget = 0;
1072                 victim->target = 0;
1073
1074                 XYZ rotatetarget;
1075                 rotatetarget = coords - victim->coords;
1076                 Normalise(&rotatetarget);
1077                 victim->targetyaw = -asin(0 - rotatetarget.x);
1078                 victim->targetyaw *= 360 / 6.28;
1079                 if (rotatetarget.z < 0)
1080                     victim->targetyaw = 180 - victim->targetyaw;
1081
1082                 victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
1083
1084                 victim->lastattack3 = victim->lastattack2;
1085                 victim->lastattack2 = victim->lastattack;
1086                 victim->lastattack = victim->animTarget;
1087             } else {
1088                 victim->animTarget = sweepanim;
1089                 victim->frameTarget = 0;
1090                 victim->target = 0;
1091
1092                 XYZ rotatetarget;
1093                 rotatetarget = coords - victim->coords;
1094                 Normalise(&rotatetarget);
1095                 victim->targetyaw = -asin(0 - rotatetarget.x);
1096                 victim->targetyaw *= 360 / 6.28;
1097                 if (rotatetarget.z < 0)
1098                     victim->targetyaw = 180 - victim->targetyaw;
1099
1100                 victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
1101
1102                 victim->lastattack3 = victim->lastattack2;
1103                 victim->lastattack2 = victim->lastattack;
1104                 victim->lastattack = victim->animTarget;
1105             }
1106         }
1107
1108     velocity = 0;
1109     victim->velocity = 0;
1110
1111     if (aitype != playercontrolled)
1112         feint = 0;
1113     if (aitype != playercontrolled && Random() % 3 == 0 && escapednum < 2 && difficulty == 2)
1114         feint = 1;
1115     if (aitype != playercontrolled && Random() % 5 == 0 && escapednum < 2 && difficulty == 1)
1116         feint = 1;
1117     if (aitype != playercontrolled && Random() % 10 == 0 && escapednum < 2 && difficulty == 0)
1118         feint = 1;
1119
1120     if (victim->id == 0 && animation[victim->animTarget].attack == reversal)
1121         numreversals++;
1122 }
1123
1124 /* EFFECT
1125  * get hurt
1126  */
1127 void Person::DoDamage(float howmuch)
1128 {
1129     // subtract health (temporary?)
1130     if (tutoriallevel != 1)
1131         damage += howmuch / power;
1132     // stats?
1133     if (id != 0)
1134         damagedealt += howmuch / power;
1135     if (id == 0)
1136         damagetaken += howmuch / power;
1137
1138     // reset bonuses
1139     if (id == 0 && (bonus == solidhit || bonus == twoxcombo || bonus == threexcombo || bonus == fourxcombo || bonus == megacombo))
1140         bonus = 0;
1141     // subtract health
1142     if (tutoriallevel != 1)
1143         permanentdamage += howmuch / 2 / power;
1144     if (tutoriallevel != 1)
1145         superpermanentdamage += howmuch / 4 / power;
1146     // visual effects
1147     if (permanentdamage > damagetolerance / 2 && permanentdamage - howmuch < damagetolerance / 2 && Random() % 2)
1148         DoBlood(1, 255);
1149     if ((permanentdamage > damagetolerance * .8 && Random() % 2 && !deathbleeding) || spurt)
1150         DoBlood(1, 255);
1151     spurt = 0;
1152     if (id == 0)
1153         camerashake += howmuch / 100;
1154     if (id == 0 && ((howmuch > 50 && damage > damagetolerance / 2)))
1155         blackout = damage / damagetolerance;
1156     if (blackout > 1)
1157         blackout = 1;
1158
1159     // cancel attack?
1160     if (aitype == passivetype && damage < damagetolerance && ((tutoriallevel != 1 || cananger) && hostile))
1161         aitype = attacktypecutoff;
1162     if (tutoriallevel != 1 && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) {
1163         if (abs(Random() % 2) == 0) {
1164             aitype = gethelptype;
1165             lastseentime = 12;
1166         } else
1167             aitype = attacktypecutoff;
1168         ally = 0;
1169     }
1170
1171     if (howmuch > damagetolerance * 50 && skeleton.free != 2) {
1172         XYZ flatvelocity2;
1173         XYZ flatfacing2;
1174         for (int i = 0; i < skeleton.num_joints; i++) {
1175             if (skeleton.free) {
1176                 flatvelocity2 = skeleton.joints[i].velocity;
1177                 flatfacing2 = skeleton.joints[i].position * scale + coords;
1178             } else {
1179                 flatvelocity2 = velocity;
1180                 flatfacing2 = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
1181             }
1182             flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
1183             flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
1184             flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
1185             Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
1186             Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
1187             Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
1188         }
1189
1190         emit_sound_at(splattersound, coords);
1191
1192         skeleton.free = 2;
1193         DoDamage(10000);
1194         RagDoll(0);
1195         if (!dead && creature == wolftype) {
1196             award_bonus(0, Wolfbonus);
1197         }
1198         dead = 2;
1199         coords = 20;
1200     }
1201
1202     // play sounds
1203     if (tutoriallevel != 1 || id == 0)
1204         if (speechdelay <= 0 && !dead && aitype != playercontrolled) {
1205             int whichsound = -1;
1206
1207             if (creature == wolftype) {
1208                 int i = abs(Random() % 2);
1209                 if (i == 0)
1210                     whichsound = snarlsound;
1211                 if (i == 1)
1212                     whichsound = snarl2sound;
1213                 envsound[numenvsounds] = coords;
1214                 envsoundvol[numenvsounds] = 16;
1215                 envsoundlife[numenvsounds] = .4;
1216                 numenvsounds++;
1217             }
1218             if (creature == rabbittype) {
1219                 int i = abs(Random() % 2);
1220                 if (i == 0)
1221                     whichsound = rabbitpainsound;
1222                 if (i == 1 && damage > damagetolerance)
1223                     whichsound = rabbitpain1sound;
1224                 envsound[numenvsounds] = coords;
1225                 envsoundvol[numenvsounds] = 16;
1226                 envsoundlife[numenvsounds] = .4;
1227                 numenvsounds++;
1228             }
1229
1230             if (whichsound != -1) {
1231                 emit_sound_at(whichsound, coords);
1232             }
1233         }
1234     speechdelay = .3;
1235 }
1236
1237 /* EFFECT
1238  * calculate/animate head facing direction?
1239  */
1240 void Person::DoHead()
1241 {
1242     static XYZ rotatearound;
1243     static XYZ facing;
1244     static float lookspeed = 500;
1245
1246     if (!freeze && !winfreeze) {
1247
1248         //head facing
1249         targetheadyaw = (float)((int)((0 - yaw - targetheadyaw + 180) * 100) % 36000) / 100;
1250         targetheadpitch = (float)((int)(targetheadpitch * 100) % 36000) / 100;
1251
1252         while (targetheadyaw > 180)targetheadyaw -= 360;
1253         while (targetheadyaw < -180)targetheadyaw += 360;
1254
1255         if (targetheadyaw > 160)
1256             targetheadpitch = targetheadpitch * -1;
1257         if (targetheadyaw < -160)
1258             targetheadpitch = targetheadpitch * -1;
1259         if (targetheadyaw > 160)
1260             targetheadyaw = targetheadyaw - 180;
1261         if (targetheadyaw < -160)
1262             targetheadyaw = targetheadyaw + 180;
1263
1264         if (targetheadpitch > 120)
1265             targetheadpitch = 120;
1266         if (targetheadpitch < -120)
1267             targetheadpitch = -120;
1268         if (targetheadyaw > 120)
1269             targetheadyaw = 120;
1270         if (targetheadyaw < -120)
1271             targetheadyaw = -120;
1272
1273         if (!isIdle())
1274             targetheadpitch = 0;
1275         if (isIdle()) {
1276             if (targetheadyaw > 80)
1277                 targetheadyaw = 80;
1278             if (targetheadyaw < -80)
1279                 targetheadyaw = -80;
1280             if (targetheadpitch > 50)
1281                 targetheadpitch = 50;
1282             if (targetheadpitch < -50)
1283                 targetheadpitch = -50;
1284         }
1285
1286         if (abs(headyaw - targetheadyaw) < multiplier * lookspeed)
1287             headyaw = targetheadyaw;
1288         else if (headyaw > targetheadyaw) {
1289             headyaw -= multiplier * lookspeed;
1290         } else if (headyaw < targetheadyaw) {
1291             headyaw += multiplier * lookspeed;
1292         }
1293
1294         if (abs(headpitch - targetheadpitch) < multiplier * lookspeed / 2)
1295             headpitch = targetheadpitch;
1296         else if (headpitch > targetheadpitch) {
1297             headpitch -= multiplier * lookspeed / 2;
1298         } else if (headpitch < targetheadpitch) {
1299             headpitch += multiplier * lookspeed / 2;
1300         }
1301
1302         rotatearound = jointPos(neck);
1303         jointPos(head) = rotatearound + DoRotation(jointPos(head) - rotatearound, headpitch, 0, 0);
1304
1305         facing = 0;
1306         facing.z = -1;
1307         if (animTarget != bounceidleanim && animTarget != fightidleanim && animTarget != wolfidle && animTarget != knifefightidleanim && animTarget != drawrightanim && animTarget != drawleftanim && animTarget != walkanim) {
1308             facing = DoRotation(facing, headpitch * .4, 0, 0);
1309             facing = DoRotation(facing, 0, headyaw * .4, 0);
1310         }
1311
1312         if (animTarget == bounceidleanim || animTarget == fightidleanim || animTarget == wolfidle || animTarget == knifefightidleanim || animTarget == drawrightanim || animTarget == drawleftanim) {
1313             facing = DoRotation(facing, headpitch * .8, 0, 0);
1314             facing = DoRotation(facing, 0, headyaw * .8, 0);
1315         }
1316
1317         if (animTarget == walkanim) {
1318             facing = DoRotation(facing, headpitch * .6, 0, 0);
1319             facing = DoRotation(facing, 0, headyaw * .6, 0);
1320         }
1321
1322         skeleton.specialforward[0] = facing;
1323         //skeleton.specialforward[0]=DoRotation(facing,0,yaw,0);
1324         for (int i = 0; i < skeleton.num_muscles; i++) {
1325             if (skeleton.muscles[i].visible && (skeleton.muscles[i].parent1->label == head || skeleton.muscles[i].parent2->label == head)) {
1326                 skeleton.FindRotationMuscle(i, animTarget);
1327             }
1328         }
1329     }
1330 }
1331
1332 /* EFFECT
1333  * ragdolls character?
1334  */
1335 void Person::RagDoll(bool checkcollision)
1336 {
1337     static XYZ change;
1338     static int l, i, j;
1339     static float speed;
1340     if (!skeleton.free) {
1341         if (id == 0)
1342             numfalls++;
1343         if (id == 0 && isFlip())
1344             numflipfail++;
1345
1346         escapednum = 0;
1347
1348         facing = 0;
1349         facing.z = 1;
1350         facing = DoRotation(facing, 0, yaw, 0);
1351
1352         skeleton.freetime = 0;
1353
1354         skeleton.longdead = 0;
1355
1356         skeleton.free = 1;
1357         skeleton.broken = 0;
1358         skeleton.spinny = 1;
1359         freefall = 1;
1360         skeleton.freefall = 1;
1361
1362         if (!isnormal(velocity.x)) velocity.x = 0;
1363         if (!isnormal(velocity.y)) velocity.y = 0;
1364         if (!isnormal(velocity.z)) velocity.z = 0;
1365         if (!isnormal(yaw)) yaw = 0;
1366         if (!isnormal(coords.x)) coords = 0;
1367         if (!isnormal(tilt)) tilt = 0;
1368         if (!isnormal(tilt2)) tilt2 = 0;
1369
1370         for (int i = 0; i < skeleton.num_joints; i++) {
1371             skeleton.joints[i].delay = 0;
1372             skeleton.joints[i].locked = 0;
1373             skeleton.joints[i].position = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
1374             if (!isnormal(skeleton.joints[i].position.x)) skeleton.joints[i].position = DoRotation(skeleton.joints[i].position, 0, yaw, 0);
1375             if (!isnormal(skeleton.joints[i].position.x)) skeleton.joints[i].position = coords;
1376             skeleton.joints[i].position.y += .1;
1377             skeleton.joints[i].oldposition = skeleton.joints[i].position;
1378             skeleton.joints[i].realoldposition = skeleton.joints[i].position * scale + coords;
1379         }
1380
1381         for (int i = 0; i < skeleton.num_joints; i++) {
1382             skeleton.joints[i].velocity = 0;
1383             skeleton.joints[i].velchange = 0;
1384         }
1385         skeleton.DoConstraints(&coords, &scale);
1386         if (animation[animCurrent].height == lowheight || animation[animTarget].height == lowheight) {
1387             skeleton.DoConstraints(&coords, &scale);
1388             skeleton.DoConstraints(&coords, &scale);
1389             skeleton.DoConstraints(&coords, &scale);
1390             skeleton.DoConstraints(&coords, &scale);
1391         }
1392
1393         speed = animation[animTarget].speed[frameTarget] * 2;
1394         if (animation[animCurrent].speed[frameCurrent] > animation[animTarget].speed[frameTarget]) {
1395             speed = animation[animCurrent].speed[frameCurrent] * 2;
1396         }
1397         if (transspeed)
1398             speed = transspeed * 2;
1399
1400         speed *= speedmult;
1401
1402         for (int i = 0; i < skeleton.num_joints; i++) {
1403             if ((animation[animCurrent].attack != reversed || animCurrent == swordslashreversedanim) && animCurrent != rabbitkickanim && !isLanding() && !wasLanding() && animation[animCurrent].height == animation[animTarget].height)
1404                 skeleton.joints[i].velocity = velocity / scale + facing * 5 + DoRotation(DoRotation(DoRotation((animation[animTarget].position[i][frameTarget] - animation[animCurrent].position[i][frameCurrent]) * speed, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
1405             else
1406                 skeleton.joints[i].velocity = velocity / scale + facing * 5;
1407             change.x = (float)(Random() % 100) / 100;
1408             change.y = (float)(Random() % 100) / 100;
1409             change.z = (float)(Random() % 100) / 100;
1410             skeleton.joints[i].velocity += change;
1411             skeleton.joints[abs(Random() % skeleton.num_joints)].velocity -= change;
1412
1413             change.x = (float)(Random() % 100) / 100;
1414             change.y = (float)(Random() % 100) / 100;
1415             change.z = (float)(Random() % 100) / 100;
1416             skeleton.joints[i].velchange += change;
1417             skeleton.joints[abs(Random() % skeleton.num_joints)].velchange -= change;
1418         }
1419
1420         if (checkcollision) {
1421             XYZ average;
1422             XYZ lowpoint;
1423             XYZ colpoint;
1424             int howmany;
1425             average = 0;
1426             howmany = 0;
1427             for (j = 0; j < skeleton.num_joints; j++) {
1428                 average += skeleton.joints[j].position;
1429                 howmany++;
1430             }
1431             average /= howmany;
1432             coords += average * scale;
1433             for (j = 0; j < skeleton.num_joints; j++) {
1434                 skeleton.joints[j].position -= average;
1435             }
1436
1437             whichpatchx = coords.x / (terrain.size / subdivision * terrain.scale);
1438             whichpatchz = coords.z / (terrain.size / subdivision * terrain.scale);
1439             if (terrain.patchobjectnum[whichpatchx][whichpatchz])
1440                 for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
1441                     i = terrain.patchobjects[whichpatchx][whichpatchz][l];
1442                     lowpoint = coords;
1443                     lowpoint.y += 1;
1444                     if (SphereCheck(&lowpoint, 3, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
1445                         coords.x = lowpoint.x;
1446                         coords.z = lowpoint.z;
1447                     }
1448                 }
1449         }
1450
1451         yaw = 0;
1452         updatedelay = 0;
1453
1454         velocity = 0;
1455         for (int i = 0; i < skeleton.num_joints; i++) {
1456             velocity += skeleton.joints[i].velocity * scale;
1457         }
1458         velocity /= skeleton.num_joints;
1459
1460         // drop weapon
1461         if (Random() % 2 == 0) {
1462             if (weaponactive != -1 && animTarget != rabbitkickanim && num_weapons > 0) {
1463                 weapons[weaponids[0]].drop(jointVel(righthand) * scale * -.3, jointVel(righthand) * scale);
1464                 weapons[weaponids[0]].velocity.x += .01;
1465                 num_weapons--;
1466                 if (num_weapons) {
1467                     weaponids[0] = weaponids[num_weapons];
1468                     if (weaponstuck == num_weapons)
1469                         weaponstuck = 0;
1470                 }
1471                 weaponactive = -1;
1472                 for (unsigned i = 0; i < Person::players.size(); i++) {
1473                     Person::players[i]->wentforweapon = 0;
1474                 }
1475             }
1476         }
1477
1478         animTarget = bounceidleanim;
1479         animCurrent = bounceidleanim;
1480         frameTarget = 0;
1481         frameCurrent = 0;
1482     }
1483 }
1484
1485
1486
1487 /* EFFECT
1488  */
1489 void Person::FootLand(int which, float opacity)
1490 {
1491     static XYZ terrainlight;
1492     static XYZ footvel, footpoint;
1493     if (opacity >= 1 || skiddelay <= 0)
1494         if (opacity > 1) {
1495             footvel = 0;
1496             if (which == 0)
1497                 footpoint = DoRotation(jointPos(leftfoot), 0, yaw, 0) * scale + coords;
1498             if (which == 1)
1499                 footpoint = DoRotation(jointPos(rightfoot), 0, yaw, 0) * scale + coords;
1500             //footpoint.y=coords.y;
1501             if (distsq(&footpoint, &viewer))
1502                 Sprite::MakeSprite(cloudsprite, footpoint, footvel, 1, 1, 1, .5, .2 * opacity);
1503         } else if (environment == snowyenvironment && onterrain && terrain.getOpacity(coords.x, coords.z) < .2) {
1504             footvel = velocity / 5;
1505             if (footvel.y < .8)
1506                 footvel.y = .8;
1507             if (which == 0)
1508                 footpoint = DoRotation(jointPos(leftfoot), 0, yaw, 0) * scale + coords;
1509             if (which == 1)
1510                 footpoint = DoRotation(jointPos(rightfoot), 0, yaw, 0) * scale + coords;
1511             footpoint.y = terrain.getHeight(footpoint.x, footpoint.z);
1512             terrainlight = terrain.getLighting(footpoint.x, footpoint.z);
1513             if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4)
1514                 Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7 * opacity);
1515             if (opacity >= 1 || detail == 2)
1516                 if (detail == 2)
1517                     if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4)
1518                         terrain.MakeDecal(footprintdecal, footpoint, .2, 1 * opacity, yaw);
1519         } else if (environment == grassyenvironment && onterrain && terrain.getOpacity(coords.x, coords.z) < .2) {
1520             footvel = velocity / 5;
1521             if (footvel.y < .8)
1522                 footvel.y = .8;
1523             if (which == 0)
1524                 footpoint = DoRotation(jointPos(leftfoot), 0, yaw, 0) * scale + coords;
1525             if (which == 1)
1526                 footpoint = DoRotation(jointPos(rightfoot), 0, yaw, 0) * scale + coords;
1527             footpoint.y = terrain.getHeight(footpoint.x, footpoint.z);
1528             terrainlight = terrain.getLighting(footpoint.x, footpoint.z);
1529             if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4)
1530                 Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5 * opacity);
1531         } else if (environment == desertenvironment && onterrain && terrain.getOpacity(coords.x, coords.z) < .2) {
1532             footvel = velocity / 5;
1533             if (footvel.y < .8)
1534                 footvel.y = .8;
1535             if (which == 0)
1536                 footpoint = DoRotation(jointPos(leftfoot), 0, yaw, 0) * scale + coords;
1537             if (which == 1)
1538                 footpoint = DoRotation(jointPos(rightfoot), 0, yaw, 0) * scale + coords;
1539             footpoint.y = terrain.getHeight(footpoint.x, footpoint.z);
1540             terrainlight = terrain.getLighting(footpoint.x, footpoint.z);
1541             if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4)
1542                 Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7 * opacity);
1543             if (opacity >= 1 || detail == 2)
1544                 if (detail == 2)
1545                     if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4)
1546                         terrain.MakeDecal(footprintdecal, footpoint, .2, .25 * opacity, yaw);
1547         } else if (isLanding() || animTarget == jumpupanim || isLandhard()) {
1548             footvel = velocity / 5;
1549             if (footvel.y < .8)
1550                 footvel.y = .8;
1551             if (which == 0)
1552                 footpoint = DoRotation(jointPos(leftfoot), 0, yaw, 0) * scale + coords;
1553             if (which == 1)
1554                 footpoint = DoRotation(jointPos(rightfoot), 0, yaw, 0) * scale + coords;
1555             //footpoint.y=coords.y;
1556             if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4)
1557                 Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, 1, 1, 1, .5, .2 * opacity);
1558         }
1559 }
1560
1561 /* EFFECT
1562  * make a puff effect at a body part (dust effect?)
1563  */
1564 void Person::Puff(int whichlabel)
1565 {
1566     static XYZ footvel, footpoint;
1567
1568     footvel = 0;
1569     footpoint = DoRotation(jointPos(whichlabel), 0, yaw, 0) * scale + coords;
1570     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .9, .3);
1571 }
1572
1573 /* EFFECT
1574  * I think I added this in an attempt to clean up code
1575  */
1576 void Person::setAnimation(int animation)
1577 {
1578     animTarget = animation;
1579     frameTarget = 0;
1580     target = 0;
1581 }
1582
1583 /* EFFECT
1584  * MONSTER
1585  * TODO: ???
1586  */
1587 void Person::DoAnimations()
1588 {
1589     if (!skeleton.free) {
1590         static float oldtarget;
1591
1592         if (isIdle() && animCurrent != getIdle())
1593             normalsupdatedelay = 0;
1594
1595         if (animTarget == tempanim || animCurrent == tempanim) {
1596             animation[tempanim] = tempanimation;
1597         }
1598         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
1599             float gLoc[3];
1600             float vel[3];
1601             gLoc[0] = coords.x;
1602             gLoc[1] = coords.y;
1603             gLoc[2] = coords.z;
1604             vel[0] = velocity.x;
1605             vel[1] = velocity.y;
1606             vel[2] = velocity.z;
1607
1608             if (id == 0) {
1609                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc, vel);
1610                 OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
1611             }
1612             if (((velocity.y < -15) || (crouchkeydown && velocity.y < -8)) && abs(velocity.y) * 4 > fast_sqrt(velocity.x * velocity.x * velocity.z * velocity.z))
1613                 landhard = 1;
1614             if (!crouchkeydown && velocity.y >= -15)
1615                 landhard = 0;
1616         }
1617         if ((animCurrent == jumpupanim || animTarget == jumpdownanim)/*&&velocity.y<40*/ && !isFlip() && (!isLanding() && !isLandhard()) && ((crouchkeydown && !crouchtogglekeydown))) {
1618             XYZ targfacing;
1619             targfacing = 0;
1620             targfacing.z = 1;
1621
1622             targfacing = DoRotation(targfacing, 0, targetyaw, 0);
1623
1624             if (normaldotproduct(targfacing, velocity) >= -.3)
1625                 animTarget = flipanim;
1626             else
1627                 animTarget = backflipanim;
1628             crouchtogglekeydown = 1;
1629             frameTarget = 0;
1630             target = 0;
1631
1632             if (id == 0)
1633                 numflipped++;
1634         }
1635
1636         if (animation[animTarget].attack != reversed)
1637             feint = 0;
1638         if (!crouchkeydown || (isLanding() || isLandhard()) || (wasLanding() || wasLandhard())) {
1639             crouchtogglekeydown = 0;
1640             if (aitype == playercontrolled)
1641                 feint = 0;
1642         } else {
1643             if (!crouchtogglekeydown && animation[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain))
1644                 feint = 1;
1645             if (!isFlip())
1646                 crouchtogglekeydown = 1;
1647         }
1648
1649
1650         if (animation[animTarget].attack || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim) {
1651             if (detail)
1652                 normalsupdatedelay = 0;
1653         }
1654
1655         if (target >= 1) {
1656             if (animTarget == rollanim && frameTarget == 3 && onfire) {
1657                 onfire = 0;
1658                 emit_sound_at(fireendsound, coords);
1659                 pause_sound(stream_firesound);
1660                 deathbleeding = 0;
1661             }
1662
1663             if (animTarget == rabbittacklinganim && frameTarget == 1) {
1664                 if (victim->aitype == attacktypecutoff && victim->stunned <= 0 && victim->surprised <= 0 && victim->id != 0)
1665                     Reverse();
1666                 if (animTarget == rabbittacklinganim && frameTarget == 1 && !victim->isCrouch() && victim->animTarget != backhandspringanim) {
1667                     if (normaldotproduct(victim->facing, facing) > 0)
1668                         victim->animTarget = rabbittackledbackanim;
1669                     else
1670                         victim->animTarget = rabbittackledfrontanim;
1671                     victim->frameTarget = 2;
1672                     victim->target = 0;
1673                     victim->yaw = yaw;
1674                     victim->targetyaw = yaw;
1675                     if (victim->aitype == gethelptype)
1676                         victim->DoDamage(victim->damagetolerance - victim->damage);
1677                     //victim->DoDamage(30);
1678                     if (creature == wolftype) {
1679                         DoBloodBig(0, 255);
1680                         emit_sound_at(clawslicesound, victim->coords);
1681                         victim->spurt = 1;
1682                         victim->DoBloodBig(1 / victim->armorhead, 210);
1683                     }
1684                     award_bonus(id, TackleBonus,
1685                                 victim->aitype == gethelptype ? 50 : 0);
1686                 }
1687             }
1688
1689             if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (animation[animTarget].label[frameTarget] || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
1690                 if (weapons[weaponids[0]].getType() == knife) {
1691                     if (weaponactive == -1)
1692                         weaponactive = 0;
1693                     else if (weaponactive == 0)
1694                         weaponactive = -1;
1695
1696                     if (weaponactive == -1) {
1697                         emit_sound_at(knifesheathesound, coords);
1698                     }
1699                     if (weaponactive != -1) {
1700                         emit_sound_at(knifedrawsound, coords, 128);
1701                     }
1702                 }
1703                 drawtogglekeydown = 1;
1704             }
1705             //Footstep sounds
1706             if (tutoriallevel != 1 || id == 0)
1707                 if ((animation[animTarget].label[frameTarget] && (animation[animTarget].label[frameTarget] < 5 || animation[animTarget].label[frameTarget] == 8))/*||(animTarget==rollanim&&frameTarget==animation[rollanim].numframes-1)*/) {
1708                     int whichsound;
1709                     if (onterrain) {
1710                         if (terrain.getOpacity(coords.x, coords.z) < .2) {
1711                             if (animation[animTarget].label[frameTarget] == 1)
1712                                 whichsound = footstepsound;
1713                             else
1714                                 whichsound = footstepsound2;
1715                             if (animation[animTarget].label[frameTarget] == 1)
1716                                 FootLand(0, 1);
1717                             if (animation[animTarget].label[frameTarget] == 2)
1718                                 FootLand(1, 1);
1719                             if (animation[animTarget].label[frameTarget] == 3 && isRun()) {
1720                                 FootLand(1, 1);
1721                                 FootLand(0, 1);
1722                             }
1723
1724                         }
1725                         if (terrain.getOpacity(coords.x, coords.z) >= .2) {
1726                             if (animation[animTarget].label[frameTarget] == 1)
1727                                 whichsound = footstepsound3;
1728                             else
1729                                 whichsound = footstepsound4;
1730                         }
1731                     }
1732                     if (!onterrain) {
1733                         if (animation[animTarget].label[frameTarget] == 1)
1734                             whichsound = footstepsound3;
1735                         else
1736                             whichsound = footstepsound4;
1737                     }
1738                     if (animation[animTarget].label[frameTarget] == 4 && (weaponactive == -1 || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
1739                         if (animation[animTarget].attack != neutral) {
1740                             unsigned r = abs(Random() % 3);
1741                             if (r == 0)
1742                                 whichsound = lowwhooshsound;
1743                             if (r == 1)
1744                                 whichsound = midwhooshsound;
1745                             if (r == 2)
1746                                 whichsound = highwhooshsound;
1747                         }
1748                         if (animation[animTarget].attack == neutral)
1749                             whichsound = movewhooshsound;
1750                     } else if (animation[animTarget].label[frameTarget] == 4)
1751                         whichsound = knifeswishsound;
1752                     if (animation[animTarget].label[frameTarget] == 8 && tutoriallevel != 1)
1753                         whichsound = landsound2;
1754
1755                     emit_sound_at(whichsound, coords, 256.);
1756
1757                     if (id == 0)
1758                         if (whichsound == footstepsound || whichsound == footstepsound2 || whichsound == footstepsound3 || whichsound == footstepsound4) {
1759                             envsound[numenvsounds] = coords;
1760                             if (animTarget == wolfrunninganim || animTarget == rabbitrunninganim)
1761                                 envsoundvol[numenvsounds] = 15;
1762                             else
1763                                 envsoundvol[numenvsounds] = 6;
1764                             envsoundlife[numenvsounds] = .4;
1765                             numenvsounds++;
1766                         }
1767
1768                     if (animation[animTarget].label[frameTarget] == 3) {
1769                         whichsound--;
1770                         emit_sound_at(whichsound, coords, 128.);
1771                     }
1772                 }
1773
1774             //Combat sounds
1775             if (tutoriallevel != 1 || id == 0)
1776                 if (speechdelay <= 0)
1777                     if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
1778                         if ((animation[animTarget].label[frameTarget] && (animation[animTarget].label[frameTarget] < 5 || animation[animTarget].label[frameTarget] == 8))/*||(animTarget==rollanim&&frameTarget==animation[rollanim].numframes-1)*/) {
1779                             int whichsound = -1;
1780                             if (animation[animTarget].label[frameTarget] == 4 && aitype != playercontrolled) {
1781                                 if (animation[animTarget].attack != neutral) {
1782                                     unsigned r = abs(Random() % 4);
1783                                     if (creature == rabbittype) {
1784                                         if (r == 0) whichsound = rabbitattacksound;
1785                                         if (r == 1) whichsound = rabbitattack2sound;
1786                                         if (r == 2) whichsound = rabbitattack3sound;
1787                                         if (r == 3) whichsound = rabbitattack4sound;
1788                                     }
1789                                     if (creature == wolftype) {
1790                                         if (r == 0) whichsound = barksound;
1791                                         if (r == 1) whichsound = bark2sound;
1792                                         if (r == 2) whichsound = bark3sound;
1793                                         if (r == 3) whichsound = barkgrowlsound;
1794                                     }
1795                                     speechdelay = .3;
1796                                 }
1797                             }
1798
1799                             if (whichsound != -1) {
1800                                 emit_sound_at(whichsound, coords);
1801                             }
1802                         }
1803
1804
1805
1806             if ((!wasLanding() && !wasLandhard()) && animCurrent != getIdle() && (isLanding() || isLandhard())) {
1807                 FootLand(0, 1);
1808                 FootLand(1, 1);
1809             }
1810
1811             transspeed = 0;
1812             currentoffset = targetoffset;
1813             frameTarget = frameCurrent;
1814             animCurrent = animTarget;
1815             frameTarget++;
1816
1817             if (animTarget == removeknifeanim && animation[animTarget].label[frameCurrent] == 5) {
1818                 for (unsigned i = 0; i < weapons.size(); i++) {
1819                     if (weapons[i].owner == -1)
1820                         if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
1821                             if (distsq(&coords, &weapons[i].position) >= 1) {
1822                                 if (weapons[i].getType() != staff) {
1823                                     emit_sound_at(knifedrawsound, coords, 128.);
1824                                 }
1825
1826                                 takeWeapon(i);
1827                             }
1828                         }
1829                 }
1830             }
1831
1832             if (animTarget == crouchremoveknifeanim && animation[animTarget].label[frameCurrent] == 5) {
1833                 for (unsigned i = 0; i < weapons.size(); i++) {
1834                     bool willwork = true;
1835                     if (weapons[i].owner != -1)
1836                         if (Person::players[weapons[i].owner]->weaponstuck != -1)
1837                             if (Person::players[weapons[i].owner]->weaponids[Person::players[weapons[i].owner]->weaponstuck] == int(i))
1838                                 if (Person::players[weapons[i].owner]->num_weapons > 1)
1839                                     willwork = 0;
1840                     if ((weapons[i].owner == -1) || (hasvictim && (weapons[i].owner == int(victim->id)) && victim->skeleton.free))
1841                         if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && weaponactive == -1) {
1842                             if (distsq(&coords, &weapons[i].position) < 1 || hasvictim) {
1843                                 bool fleshstuck = false;
1844                                 if (weapons[i].owner != -1)
1845                                     if (victim->weaponstuck != -1) {
1846                                         if (victim->weaponids[victim->weaponstuck] == int(i)) {
1847                                             fleshstuck = true;
1848                                         }
1849                                     }
1850                                 if (fleshstuck) {
1851                                     emit_sound_at(fleshstabremovesound, coords, 128.);
1852                                 } else {
1853                                     if (weapons[i].getType() != staff) {
1854                                         emit_sound_at(knifedrawsound, coords, 128.);
1855                                     }
1856                                 }
1857                                 if (weapons[i].owner != -1) {
1858                                     victim = Person::players[weapons[i].owner];
1859                                     if (victim->num_weapons == 1)
1860                                         victim->num_weapons = 0;
1861                                     else
1862                                         victim->num_weapons = 1;
1863
1864                                     //victim->weaponactive=-1;
1865                                     victim->skeleton.longdead = 0;
1866                                     victim->skeleton.free = 1;
1867                                     victim->skeleton.broken = 0;
1868
1869                                     for (int j = 0; j < victim->skeleton.num_joints; j++) {
1870                                         victim->skeleton.joints[j].velchange = 0;
1871                                         victim->skeleton.joints[j].locked = 0;
1872                                     }
1873
1874                                     XYZ relative;
1875                                     relative = 0;
1876                                     relative.y = 10;
1877                                     Normalise(&relative);
1878                                     XYZ footvel, footpoint;
1879                                     footvel = 0;
1880                                     footpoint = weapons[i].position;
1881                                     if (victim->weaponstuck != -1) {
1882                                         if (victim->weaponids[victim->weaponstuck] == int(i)) {
1883                                             if (bloodtoggle)
1884                                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
1885                                             weapons[i].bloody = 2;
1886                                             weapons[i].blooddrip = 5;
1887                                             victim->weaponstuck = -1;
1888                                         }
1889                                     }
1890                                     if (victim->num_weapons > 0) {
1891                                         if (victim->weaponstuck != 0 && victim->weaponstuck != -1)
1892                                             victim->weaponstuck = 0;
1893                                         if (victim->weaponids[0] == int(i))
1894                                             victim->weaponids[0] = victim->weaponids[victim->num_weapons];
1895                                     }
1896
1897                                     victim->jointVel(abdomen) += relative * 6;
1898                                     victim->jointVel(neck) += relative * 6;
1899                                     victim->jointVel(rightshoulder) += relative * 6;
1900                                     victim->jointVel(leftshoulder) += relative * 6;
1901                                 }
1902                                 takeWeapon(i);
1903                             }
1904                         }
1905                 }
1906             }
1907
1908             if (animCurrent == drawleftanim && animation[animTarget].label[frameCurrent] == 5) {
1909                 if (weaponactive == -1)
1910                     weaponactive = 0;
1911                 else if (weaponactive == 0) {
1912                     weaponactive = -1;
1913                     if (num_weapons == 2) {
1914                         int buffer;
1915                         buffer = weaponids[0];
1916                         weaponids[0] = weaponids[1];
1917                         weaponids[1] = buffer;
1918                     }
1919                 }
1920                 if (weaponactive == -1) {
1921                     emit_sound_at(knifesheathesound, coords, 128.);
1922                 }
1923                 if (weaponactive != -1) {
1924                     emit_sound_at(knifedrawsound, coords, 128.);
1925                 }
1926             }
1927
1928
1929             if ((animCurrent == walljumprightkickanim && animTarget == walljumprightkickanim) || (animCurrent == walljumpleftkickanim && animTarget == walljumpleftkickanim)) {
1930                 XYZ rotatetarget = DoRotation(skeleton.forward, 0, yaw, 0);
1931                 Normalise(&rotatetarget);
1932                 targetyaw = -asin(0 - rotatetarget.x);
1933                 targetyaw *= 360 / 6.28;
1934                 if (rotatetarget.z < 0)
1935                     targetyaw = 180 - targetyaw;
1936
1937                 if (animTarget == walljumprightkickanim)
1938                     targetyaw += 40;
1939                 if (animTarget == walljumpleftkickanim)
1940                     targetyaw -= 40;
1941             }
1942
1943             bool dojumpattack;
1944             dojumpattack = 0;
1945             if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && frameTarget == 3 && (jumpkeydown || attackkeydown || id != 0))
1946                 dojumpattack = 1;
1947             if (hasvictim)
1948                 if (distsq(&victim->coords, &/*Person::players[i]->*/coords) < 5 && victim->aitype == gethelptype && (attackkeydown) && !victim->skeleton.free && victim->isRun() && victim->runninghowlong >= 1)
1949                     dojumpattack = 1;
1950             if (!hostile)
1951                 dojumpattack = 0;
1952             if (dojumpattack) {
1953                 if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && id == 0) {
1954                     animTarget = rabbittackleanim;
1955                     frameTarget = 0;
1956                     emit_sound_at(jumpsound, coords);
1957                 }
1958
1959                 float closestdist;
1960                 closestdist = 0;
1961                 int closestid;
1962                 closestid = -1;
1963                 XYZ targetloc;
1964                 targetloc = velocity;
1965                 Normalise(&targetloc);
1966                 targetloc += coords;
1967                 for (unsigned i = 0; i < Person::players.size(); i++) {
1968                     if (i != id)
1969                         if (distsq(&targetloc, &Person::players[i]->coords) < closestdist || closestdist == 0) {
1970                             closestdist = distsq(&targetloc, &Person::players[i]->coords);
1971                             closestid = i;
1972                         }
1973                 }
1974                 if (closestid != -1)
1975                     if (closestdist < 5 && !Person::players[closestid]->dead && animation[Person::players[closestid]->animTarget].height != lowheight && Person::players[closestid]->animTarget != backhandspringanim) {
1976                         hasvictim = 1;
1977                         victim = Person::players[closestid];
1978                         coords = victim->coords;
1979                         animCurrent = rabbittacklinganim;
1980                         animTarget = rabbittacklinganim;
1981                         frameCurrent = 0;
1982                         frameTarget = 1;
1983                         XYZ rotatetarget;
1984                         if (coords.z != victim->coords.z || coords.x != victim->coords.x) {
1985                             rotatetarget = coords - victim->coords;
1986                             Normalise(&rotatetarget);
1987                             targetyaw = -asin(0 - rotatetarget.x);
1988                             targetyaw *= 360 / 6.28;
1989                             if (rotatetarget.z < 0)
1990                                 targetyaw = 180 - targetyaw;
1991                         }
1992                         if (animTarget != rabbitrunninganim) {
1993                             emit_sound_at(jumpsound, coords, 128.);
1994                         }
1995                     }
1996             }
1997
1998             //Move impacts
1999             float damagemult = 1 * power;
2000             if (creature == wolftype)
2001                 damagemult = 2.5 * power;
2002             if (hasvictim) {
2003                 damagemult /= victim->damagetolerance / 200;
2004             }
2005             if ((animation[animTarget].attack == normalattack || animTarget == walljumprightkickanim || animTarget == walljumpleftkickanim) && (!feint) && (victim->skeleton.free != 2 || animTarget == killanim || animTarget == dropkickanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == staffgroundsmashanim)) {
2006                 if (animTarget == spinkickanim && animation[animTarget].label[frameCurrent] == 5) {
2007                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && animation[victim->animTarget].height != lowheight) {
2008                         escapednum = 0;
2009                         if (id == 0)
2010                             camerashake += .4;
2011                         if (Random() % 2 || creature == wolftype) {
2012                             victim->spurt = 1;
2013                             DoBlood(.2, 250);
2014                             if (creature == wolftype)
2015                                 DoBloodBig(0, 250);
2016                         }
2017                         if (tutoriallevel != 1) {
2018                             emit_sound_at(heavyimpactsound, victim->coords, 128.);
2019                         }
2020                         if (creature == wolftype) {
2021                             emit_sound_at(clawslicesound, victim->coords, 128.);
2022                             victim->spurt = 1;
2023                             victim->DoBloodBig(2 / victim->armorhead, 175);
2024                         }
2025                         victim->RagDoll(0);
2026                         XYZ relative;
2027                         relative = victim->coords - coords;
2028                         relative.y = 0;
2029                         Normalise(&relative);
2030                         relative = DoRotation(relative, 0, -90, 0);
2031                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2032                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2033                         }
2034                         victim->jointVel(head) += relative * damagemult * 200;
2035                         //FootLand(1,2);
2036                         victim->Puff(head);
2037                         victim->DoDamage(damagemult * 100 / victim->protectionhead);
2038
2039                         SolidHitBonus(id);
2040                     }
2041                 }
2042
2043                 if (animTarget == wolfslapanim && animation[animTarget].label[frameCurrent] == 5) {
2044                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && animation[victim->animTarget].height != lowheight) {
2045                         escapednum = 0;
2046                         if (id == 0)
2047                             camerashake += .4;
2048                         if (Random() % 2 || creature == wolftype) {
2049                             victim->spurt = 1;
2050                             if (creature == wolftype)
2051                                 DoBloodBig(0, 235);
2052                         }
2053                         emit_sound_at(whooshhitsound, victim->coords);
2054                         if (creature == wolftype) {
2055                             emit_sound_at(clawslicesound, victim->coords, 128.);
2056                             victim->spurt = 1;
2057                             victim->DoBloodBig(2, 175);
2058                         }
2059                         victim->RagDoll(0);
2060                         XYZ relative;
2061                         relative = victim->coords - coords;
2062                         relative.y = 0;
2063                         Normalise(&relative);
2064                         relative.y -= 1;
2065                         Normalise(&relative);
2066                         relative = DoRotation(relative, 0, 90, 0);
2067                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2068                             victim->skeleton.joints[i].velocity += relative * damagemult * 20;
2069                         }
2070                         victim->jointVel(head) += relative * damagemult * 100;
2071                         //FootLand(1,2);
2072                         victim->Puff(head);
2073                         victim->DoDamage(damagemult * 50 / victim->protectionhead);
2074                     }
2075                 }
2076
2077                 if (animTarget == walljumprightkickanim && animation[animTarget].label[frameCurrent] == 5) {
2078                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != lowheight) {
2079                         escapednum = 0;
2080                         if (id == 0)
2081                             camerashake += .4;
2082                         victim->spurt = 1;
2083                         DoBlood(.2, 250);
2084                         if (tutoriallevel != 1) {
2085                             emit_sound_at(heavyimpactsound, victim->coords, 160.);
2086                         }
2087                         if (creature == wolftype) {
2088                             emit_sound_at(clawslicesound, victim->coords, 128.);
2089                             victim->spurt = 1;
2090                             victim->DoBloodBig(2 / victim->armorhead, 175);
2091                         }
2092                         victim->RagDoll(0);
2093                         XYZ relative;
2094                         relative = facing;
2095                         relative.y = 0;
2096                         Normalise(&relative);
2097                         relative = DoRotation(relative, 0, -90, 0);
2098                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2099                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2100                         }
2101                         victim->jointVel(head) += relative * damagemult * 200;
2102                         //FootLand(1,2);
2103                         victim->Puff(head);
2104                         victim->DoDamage(damagemult * 150 / victim->protectionhead);
2105
2106                         if (victim->damage > victim->damagetolerance)
2107                             award_bonus(id, style);
2108                         else
2109                             SolidHitBonus(id);
2110                     }
2111                 }
2112
2113                 if (animTarget == walljumpleftkickanim && animation[animTarget].label[frameCurrent] == 5) {
2114                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != lowheight) {
2115                         escapednum = 0;
2116                         if (id == 0)
2117                             camerashake += .4;
2118                         victim->spurt = 1;
2119                         DoBlood(.2, 250);
2120                         if (tutoriallevel != 1) {
2121                             emit_sound_at(heavyimpactsound, victim->coords, 160.);
2122                         }
2123                         if (creature == wolftype) {
2124                             emit_sound_at(clawslicesound, victim->coords, 128.);
2125                             victim->spurt = 1;
2126                             victim->DoBloodBig(2 / victim->armorhead, 175);
2127                         }
2128                         victim->RagDoll(0);
2129                         XYZ relative;
2130                         relative = facing;
2131                         relative.y = 0;
2132                         Normalise(&relative);
2133                         relative = DoRotation(relative, 0, 90, 0);
2134                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2135                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2136                         }
2137                         victim->jointVel(head) += relative * damagemult * 200;
2138                         //FootLand(1,2);
2139                         victim->Puff(head);
2140                         victim->DoDamage(damagemult * 150 / victim->protectionhead);
2141
2142                         if (victim->damage > victim->damagetolerance)
2143                             award_bonus(id, style);
2144                         else
2145                             SolidHitBonus(id);
2146                     }
2147                 }
2148
2149                 if (animTarget == blockhighleftstrikeanim && animation[animTarget].label[frameCurrent] == 5) {
2150                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != lowheight) {
2151                         escapednum = 0;
2152                         if (id == 0)
2153                             camerashake += .4;
2154                         if (Random() % 2) {
2155                             victim->spurt = 1;
2156                             DoBlood(.2, 235);
2157                         }
2158                         emit_sound_at(whooshhitsound, victim->coords);
2159                         victim->RagDoll(0);
2160                         XYZ relative;
2161                         relative = victim->coords - coords;
2162                         relative.y = 0;
2163                         Normalise(&relative);
2164                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2165                             victim->skeleton.joints[i].velocity += relative * damagemult * 30;
2166                         }
2167                         victim->jointVel(head) += relative * damagemult * 100;
2168                         //FootLand(1,2);
2169                         victim->Puff(head);
2170                         victim->DoDamage(damagemult * 50 / victim->protectionhead);
2171                     }
2172                 }
2173
2174                 if (animTarget == killanim && animation[animTarget].label[frameCurrent] == 8) {
2175                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && victim->dead) {
2176                         escapednum = 0;
2177                         if (id == 0)
2178                             camerashake += .2;
2179                         emit_sound_at(whooshhitsound, victim->coords, 128.);
2180
2181                         victim->skeleton.longdead = 0;
2182                         victim->skeleton.free = 1;
2183                         victim->skeleton.broken = 0;
2184                         victim->skeleton.spinny = 1;
2185
2186                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2187                             victim->skeleton.joints[i].velchange = 0;
2188                             victim->skeleton.joints[i].delay = 0;
2189                             victim->skeleton.joints[i].locked = 0;
2190                             //victim->skeleton.joints[i].velocity=0;
2191                         }
2192
2193                         XYZ relative;
2194                         relative = 0;
2195                         relative.y = 1;
2196                         Normalise(&relative);
2197                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2198                             victim->skeleton.joints[i].velocity.y = relative.y * 10;
2199                             victim->skeleton.joints[i].position.y += relative.y * .3;
2200                             victim->skeleton.joints[i].oldposition.y += relative.y * .3;
2201                             victim->skeleton.joints[i].realoldposition.y += relative.y * .3;
2202                         }
2203                         victim->Puff(abdomen);
2204                         victim->jointVel(abdomen).y = relative.y * 400;
2205                     }
2206                 }
2207
2208                 if (animTarget == killanim && animation[animTarget].label[frameCurrent] == 5) {
2209                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->dead) {
2210                         escapednum = 0;
2211                         if (id == 0)
2212                             camerashake += .4;
2213                         if (tutoriallevel != 1) {
2214                             emit_sound_at(heavyimpactsound, coords, 128.);
2215                         }
2216                         XYZ relative;
2217                         relative = victim->coords - coords;
2218                         relative.y = 0;
2219                         Normalise(&relative);
2220                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2221                             victim->skeleton.joints[i].velocity += relative * damagemult * 90;
2222                         }
2223                         victim->Puff(abdomen);
2224                         if (victim->dead != 2 && victim->permanentdamage > victim->damagetolerance - 250 && autoslomo) {
2225                             slomo = 1;
2226                             slomodelay = .2;
2227                         }
2228                         victim->DoDamage(damagemult * 500 / victim->protectionhigh);
2229                         victim->jointVel(abdomen) += relative * damagemult * 300;
2230                     }
2231                 }
2232
2233                 if (animTarget == dropkickanim && animation[animTarget].label[frameCurrent] == 7) {
2234                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->skeleton.free) {
2235                         escapednum = 0;
2236                         if (id == 0)
2237                             camerashake += .4;
2238                         if (tutoriallevel != 1) {
2239                             emit_sound_at(thudsound, coords);
2240                         }
2241
2242                         victim->skeleton.longdead = 0;
2243                         victim->skeleton.free = 1;
2244                         victim->skeleton.broken = 0;
2245                         victim->skeleton.spinny = 1;
2246
2247                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2248                             victim->skeleton.joints[i].velchange = 0;
2249                             //victim->skeleton.joints[i].delay=0;
2250                             victim->skeleton.joints[i].locked = 0;
2251                         }
2252                         XYZ relative;
2253                         relative = victim->coords - coords;
2254                         Normalise(&relative);
2255                         relative.y += .3;
2256                         Normalise(&relative);
2257                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2258                             victim->skeleton.joints[i].velocity += relative * damagemult * 20;
2259                         }
2260                         if (!victim->dead)
2261                             SolidHitBonus(id);
2262
2263                         victim->Puff(abdomen);
2264                         victim->DoDamage(damagemult * 20 / victim->protectionhigh);
2265                         victim->jointVel(abdomen) += relative * damagemult * 200;
2266                         staggerdelay = .5;
2267                         if (!victim->dead)
2268                             staggerdelay = 1.2;
2269
2270
2271                     }
2272                 }
2273
2274                 if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && animation[animTarget].label[frameCurrent] == 5) {
2275
2276                     if (hasvictim)
2277                         if (!victim->skeleton.free)
2278                             hasvictim = 0;
2279
2280                     if (!hasvictim) {
2281                         terrain.MakeDecal(blooddecalfast, (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2), .08, .6, Random() % 360);
2282                         emit_sound_at(knifesheathesound, coords, 128.);
2283                     }
2284
2285                     if (victim && hasvictim) {
2286                         if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
2287
2288                             XYZ where, startpoint, endpoint, movepoint, colpoint;
2289                             float rotationpoint;
2290                             int whichtri;
2291                             if (weapons[weaponids[weaponactive]].getType() == knife) {
2292                                 where = (weapons[weaponids[weaponactive]].tippoint * .6 + weapons[weaponids[weaponactive]].position * .4);
2293                                 where -= victim->coords;
2294                                 if (!victim->skeleton.free)
2295                                     where = DoRotation(where, 0, -victim->yaw, 0);
2296                                 //where=scale;
2297                                 startpoint = where;
2298                                 startpoint.y += 100;
2299                                 endpoint = where;
2300                                 endpoint.y -= 100;
2301                             }
2302                             if (weapons[weaponids[weaponactive]].getType() == sword) {
2303                                 where = weapons[weaponids[weaponactive]].position;
2304                                 where -= victim->coords;
2305                                 if (!victim->skeleton.free)
2306                                     where = DoRotation(where, 0, -victim->yaw, 0);
2307                                 startpoint = where;
2308                                 where = weapons[weaponids[weaponactive]].tippoint;
2309                                 where -= victim->coords;
2310                                 if (!victim->skeleton.free)
2311                                     where = DoRotation(where, 0, -victim->yaw, 0);
2312                                 endpoint = where;
2313                             }
2314                             if (weapons[weaponids[weaponactive]].getType() == staff) {
2315                                 where = weapons[weaponids[weaponactive]].position;
2316                                 where -= victim->coords;
2317                                 if (!victim->skeleton.free)
2318                                     where = DoRotation(where, 0, -victim->yaw, 0);
2319                                 startpoint = where;
2320                                 where = weapons[weaponids[weaponactive]].tippoint;
2321                                 where -= victim->coords;
2322                                 if (!victim->skeleton.free)
2323                                     where = DoRotation(where, 0, -victim->yaw, 0);
2324                                 endpoint = where;
2325                             }
2326                             movepoint = 0;
2327                             rotationpoint = 0;
2328                             whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
2329
2330                             if (whichtri != -1) {
2331                                 if (victim->dead != 2) {
2332                                     victim->DoDamage(abs((victim->damagetolerance - victim->permanentdamage) * 2));
2333                                     if (!victim->dead)
2334                                         award_bonus(id, FinishedBonus);
2335                                 }
2336                                 if (bloodtoggle)
2337                                     weapons[weaponids[weaponactive]].bloody = 2;
2338
2339                                 victim->skeleton.longdead = 0;
2340                                 victim->skeleton.free = 1;
2341                                 victim->skeleton.broken = 0;
2342
2343                                 for (int i = 0; i < victim->skeleton.num_joints; i++) {
2344                                     victim->skeleton.joints[i].velchange = 0;
2345                                     victim->skeleton.joints[i].locked = 0;
2346                                     //victim->skeleton.joints[i].velocity=0;
2347                                 }
2348                                 emit_sound_at(fleshstabsound, coords, 128);
2349
2350                             }
2351                             if (whichtri != -1 || weapons[weaponids[weaponactive]].bloody) {
2352                                 weapons[weaponids[weaponactive]].blooddrip += 5;
2353                                 weapons[weaponids[weaponactive]].blooddripdelay = 0;
2354                             }
2355                             if (whichtri == -1) {
2356                                 hasvictim = 0;
2357                                 emit_sound_at(knifesheathesound, coords, 128.);
2358                             }
2359                         }
2360                     }
2361                 }
2362
2363                 if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && animation[animTarget].label[frameCurrent] == 6) {
2364                     if (!hasvictim) {
2365                         emit_sound_at(knifedrawsound, coords, 128);
2366                     }
2367
2368                     if (victim && hasvictim) {
2369                         XYZ footvel, footpoint;
2370
2371                         emit_sound_at(fleshstabremovesound, coords, 128.);
2372
2373                         footvel = 0;
2374                         footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
2375
2376                         if (weapons[weaponids[weaponactive]].getType() == sword) {
2377                             XYZ where, startpoint, endpoint, movepoint;
2378                             float rotationpoint;
2379                             int whichtri;
2380
2381                             where = weapons[weaponids[weaponactive]].position;
2382                             where -= victim->coords;
2383                             if (!victim->skeleton.free)
2384                                 where = DoRotation(where, 0, -victim->yaw, 0);
2385                             startpoint = where;
2386                             where = weapons[weaponids[weaponactive]].tippoint;
2387                             where -= victim->coords;
2388                             if (!victim->skeleton.free)
2389                                 where = DoRotation(where, 0, -victim->yaw, 0);
2390                             endpoint = where;
2391
2392                             movepoint = 0;
2393                             rotationpoint = 0;
2394                             whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
2395                             footpoint += victim->coords;
2396
2397                             if (whichtri == -1) {
2398                                 footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
2399                             }
2400                         }
2401                         if (weapons[weaponids[weaponactive]].getType() == staff) {
2402                             XYZ where, startpoint, endpoint, movepoint;
2403                             float rotationpoint;
2404                             int whichtri;
2405
2406                             where = weapons[weaponids[weaponactive]].position;
2407                             where -= victim->coords;
2408                             if (!victim->skeleton.free)
2409                                 where = DoRotation(where, 0, -victim->yaw, 0);
2410                             startpoint = where;
2411                             where = weapons[weaponids[weaponactive]].tippoint;
2412                             where -= victim->coords;
2413                             if (!victim->skeleton.free)
2414                                 where = DoRotation(where, 0, -victim->yaw, 0);
2415                             endpoint = where;
2416
2417                             movepoint = 0;
2418                             rotationpoint = 0;
2419                             whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
2420                             footpoint += victim->coords;
2421
2422                             if (whichtri == -1) {
2423                                 footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
2424                             }
2425                         }
2426                         hasvictim = victim->DoBloodBigWhere(2, 220, footpoint);
2427                         if (hasvictim) {
2428                             if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
2429                                 victim->skeleton.longdead = 0;
2430                                 victim->skeleton.free = 1;
2431                                 victim->skeleton.broken = 0;
2432
2433                                 for (int i = 0; i < victim->skeleton.num_joints; i++) {
2434                                     victim->skeleton.joints[i].velchange = 0;
2435                                     victim->skeleton.joints[i].locked = 0;
2436                                     //victim->skeleton.joints[i].velocity=0;
2437                                 }
2438
2439                                 XYZ relative;
2440                                 relative = 0;
2441                                 relative.y = 10;
2442                                 Normalise(&relative);
2443                                 //victim->Puff(abdomen);
2444                                 if (bloodtoggle)
2445                                     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
2446
2447                                 if (victim->bloodloss < victim->damagetolerance) {
2448                                     victim->bloodloss += 1000;
2449                                     victim->bled = 0;
2450                                 }
2451
2452                                 victim->jointVel(abdomen) += relative * damagemult * 20;
2453                             }
2454                         }
2455                     }
2456                     if (!hasvictim && onterrain) {
2457                         weapons[weaponids[weaponactive]].bloody = 0;
2458                         weapons[weaponids[weaponactive]].blooddrip = 0;
2459                     }
2460                 }
2461
2462                 if (animTarget == upunchanim && animation[animTarget].label[frameCurrent] == 5) {
2463                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
2464                         escapednum = 0;
2465                         if (id == 0)
2466                             camerashake += .4;
2467                         if (Random() % 2) {
2468                             victim->spurt = 1;
2469                             DoBlood(.2, 235);
2470                         }
2471                         if (tutoriallevel != 1) {
2472                             emit_sound_at(heavyimpactsound, victim->coords, 128);
2473                         }
2474
2475                         victim->RagDoll(0);
2476                         XYZ relative;
2477                         relative = victim->coords - coords;
2478                         relative.y = 0;
2479                         Normalise(&relative);
2480                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2481                             victim->skeleton.joints[i].velocity = relative * 30;
2482                         }
2483                         victim->jointVel(head) += relative * damagemult * 150;
2484
2485                         victim->frameTarget = 0;
2486                         victim->animTarget = staggerbackhardanim;
2487                         victim->targetyaw = targetyaw + 180;
2488                         victim->target = 0;
2489                         victim->stunned = 1;
2490
2491                         victim->Puff(head);
2492                         victim->Puff(abdomen);
2493                         victim->DoDamage(damagemult * 60 / victim->protectionhigh);
2494
2495                         SolidHitBonus(id);
2496                     }
2497                 }
2498
2499
2500                 if (animTarget == winduppunchanim && animation[animTarget].label[frameCurrent] == 5) {
2501                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 2) {
2502                         escapednum = 0;
2503                         if (id == 0)
2504                             camerashake += .4;
2505                         if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && animation[victim->animTarget].height != lowheight) {
2506                             if (tutoriallevel != 1) {
2507                                 emit_sound_at(thudsound, victim->coords);
2508                             }
2509                         } else if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && animation[victim->animTarget].height == lowheight) {
2510                             if (tutoriallevel != 1) {
2511                                 emit_sound_at(whooshhitsound, victim->coords);
2512                             }
2513                         } else {
2514                             if (tutoriallevel != 1) {
2515                                 emit_sound_at(heavyimpactsound, victim->coords);
2516                             }
2517                         }
2518
2519                         if (victim->damage > victim->damagetolerance - 60 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || animation[victim->animTarget].height == lowheight)
2520                             victim->RagDoll(0);
2521                         XYZ relative;
2522                         relative = victim->coords - coords;
2523                         relative.y = 0;
2524                         Normalise(&relative);
2525                         relative.y = .3;
2526                         Normalise(&relative);
2527                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2528                             victim->skeleton.joints[i].velocity = relative * 5;
2529                         }
2530                         victim->jointVel(abdomen) += relative * damagemult * 400;
2531
2532                         victim->frameTarget = 0;
2533                         victim->animTarget = staggerbackhardanim;
2534                         victim->targetyaw = targetyaw + 180;
2535                         victim->target = 0;
2536                         victim->stunned = 1;
2537
2538                         victim->Puff(abdomen);
2539                         victim->DoDamage(damagemult * 60 / victim->protectionhigh);
2540
2541                         SolidHitBonus(id);
2542                     }
2543                 }
2544
2545                 if (animTarget == blockhighleftanim && animation[animTarget].label[frameCurrent] == 5) {
2546                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
2547                         if (victim->id == 0)
2548                             camerashake += .4;
2549                         emit_sound_at(landsound2, victim->coords);
2550
2551                         Puff(righthand);
2552                     }
2553                 }
2554
2555                 if (animTarget == swordslashparryanim && animation[animTarget].label[frameCurrent] == 5) {
2556                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
2557                         if (victim->id == 0)
2558                             camerashake += .4;
2559
2560                         if (weaponactive != -1) {
2561                             if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
2562                                 if (weapons[victim->weaponids[0]].getType() == staff)
2563                                     weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
2564                                 if (weapons[weaponids[0]].getType() == staff)
2565                                     weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
2566
2567                                 emit_sound_at(swordstaffsound, victim->coords);
2568                             } else {
2569                                 emit_sound_at(metalhitsound, victim->coords);
2570                             }
2571                         }
2572
2573                         //Puff(righthand);
2574                     }
2575                 }
2576
2577                 if (animTarget == knifethrowanim && animation[animTarget].label[frameCurrent] == 5) {
2578                     if (weaponactive != -1) {
2579                         escapednum = 0;
2580                         XYZ aim;
2581                         aim = victim->coords + DoRotation(victim->jointPos(abdomen), 0, victim->yaw, 0) * victim->scale + victim->velocity * findDistance(&victim->coords, &coords) / 50 - (coords + DoRotation(jointPos(righthand), 0, yaw, 0) * scale);
2582                         Normalise(&aim);
2583                         weapons[weaponids[0]].thrown(aim * 50);
2584                         num_weapons--;
2585                         if (num_weapons) {
2586                             weaponids[0] = weaponids[num_weapons];
2587                         }
2588                         weaponactive = -1;
2589                     }
2590                 }
2591
2592                 if (animTarget == knifeslashstartanim && animation[animTarget].label[frameCurrent] == 5) {
2593                     if (hasvictim)
2594                         if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 &&/*animation[victim->animTarget].height!=lowheight&&*/victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
2595                             escapednum = 0;
2596                             if (tutoriallevel != 1)
2597                                 victim->DoBloodBig(1.5 / victim->armorhigh, 225);
2598
2599                             award_bonus(id, Slicebonus);
2600                             if (tutoriallevel != 1) {
2601                                 emit_sound_at(knifeslicesound, victim->coords);
2602                             }
2603                             //victim->jointVel(abdomen)+=relative*damagemult*200;
2604                             if (animation[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
2605                                 if (victim->id != 0 || difficulty == 2) {
2606                                     victim->frameTarget = 0;
2607                                     victim->animTarget = staggerbackhardanim;
2608                                     victim->targetyaw = targetyaw + 180;
2609                                     victim->target = 0;
2610                                 }
2611                             }
2612                             victim->lowreversaldelay = 0;
2613                             victim->highreversaldelay = 0;
2614                             if (aitype != playercontrolled)
2615                                 weaponmissdelay = .6;
2616
2617                             if (tutoriallevel != 1)
2618                                 if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
2619                                     weapons[weaponids[weaponactive]].bloody = 1;
2620                             if (tutoriallevel != 1)
2621                                 weapons[weaponids[weaponactive]].blooddrip += 3;
2622
2623                             XYZ footvel, footpoint;
2624                             footvel = 0;
2625                             if (skeleton.free) {
2626                                 footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
2627                             } else {
2628                                 footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
2629                             }
2630                             if (tutoriallevel != 1) {
2631                                 if (bloodtoggle)
2632                                     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .6, .3);
2633                                 footvel = DoRotation(facing, 0, 90, 0) * .8;
2634                                 //footvel.y-=.3;
2635                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
2636                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
2637                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
2638                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
2639                             }
2640                             if (tutoriallevel == 1) {
2641                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .6, .3);
2642                             }
2643                             victim->DoDamage(damagemult * 0);
2644                         }
2645                 }
2646                 if (animTarget == swordslashanim && animation[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
2647                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim) {
2648                         if (victim->weaponactive == -1 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) {
2649                             award_bonus(id, Slashbonus);
2650                             escapednum = 0;
2651                             if (tutoriallevel != 1) {
2652                                 if (normaldotproduct(victim->facing, victim->coords - coords) < 0)
2653                                     victim->DoBloodBig(2 / victim->armorhigh, 190);
2654                                 else
2655                                     victim->DoBloodBig(2 / victim->armorhigh, 185);
2656                                 victim->deathbleeding = 1;
2657                                 emit_sound_at(swordslicesound, victim->coords);
2658                             }
2659                             //victim->jointVel(abdomen)+=relative*damagemult*200;
2660                             if (tutoriallevel != 1) {
2661                                 victim->frameTarget = 0;
2662                                 victim->animTarget = staggerbackhardanim;
2663                                 victim->targetyaw = targetyaw + 180;
2664                                 victim->target = 0;
2665                             }
2666
2667                             if (tutoriallevel != 1) {
2668                                 if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
2669                                     weapons[weaponids[weaponactive]].bloody = 1;
2670                                 weapons[weaponids[weaponactive]].blooddrip += 3;
2671
2672                                 float bloodlossamount;
2673                                 bloodlossamount = 200 + abs((float)(Random() % 40)) - 20;
2674                                 victim->bloodloss += bloodlossamount / victim->armorhigh;
2675                                 //victim->bloodloss+=100*(6.5-distsq(&coords,&victim->coords));
2676                                 victim->DoDamage(damagemult * 0);
2677
2678                                 XYZ footvel, footpoint;
2679                                 footvel = 0;
2680                                 if (skeleton.free) {
2681                                     footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
2682                                 } else {
2683                                     footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
2684                                 }
2685                                 if (bloodtoggle)
2686                                     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
2687                                 footvel = DoRotation(facing, 0, 90, 0) * .8;
2688                                 footvel.y -= .3;
2689                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
2690                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
2691                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
2692                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
2693                             }
2694                         } else {
2695                             if (victim->weaponactive != -1) {
2696                                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
2697                                     if (weapons[victim->weaponids[0]].getType() == staff)
2698                                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
2699                                     if (weapons[weaponids[0]].getType() == staff)
2700                                         weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
2701
2702                                     emit_sound_at(swordstaffsound, victim->coords);
2703                                 } else {
2704                                     emit_sound_at(metalhitsound, victim->coords);
2705                                 }
2706                             }
2707
2708
2709                             XYZ aim;
2710                             victim->Puff(righthand);
2711                             victim->target = 0;
2712                             victim->frameTarget = 0;
2713                             victim->animTarget = staggerbackhighanim;
2714                             victim->targetyaw = targetyaw + 180;
2715                             victim->target = 0;
2716                             aim = DoRotation(facing, 0, 90, 0) * 21;
2717                             aim.y += 7;
2718                             weapons[victim->weaponids[0]].drop(aim * -.2, aim);
2719                             victim->num_weapons--;
2720                             if (victim->num_weapons) {
2721                                 victim->weaponids[0] = victim->weaponids[num_weapons];
2722                                 if (victim->weaponstuck == victim->num_weapons)
2723                                     victim->weaponstuck = 0;
2724                             }
2725                             victim->weaponactive = -1;
2726                             for (unsigned i = 0; i < Person::players.size(); i++) {
2727                                 Person::players[i]->wentforweapon = 0;
2728                             }
2729
2730                         }
2731                     }
2732                 }
2733
2734                 if (animTarget == staffhitanim && animation[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
2735                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
2736                         if (tutoriallevel != 1) {
2737                             weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 250;
2738                             escapednum = 0;
2739                             if (id == 0)
2740                                 camerashake += .4;
2741                             if (Random() % 2 || creature == wolftype) {
2742                                 victim->spurt = 1;
2743                             }
2744                             emit_sound_at(staffheadsound, victim->coords);
2745                         }
2746                         victim->RagDoll(0);
2747                         XYZ relative;
2748                         relative = victim->coords - coords;
2749                         relative.y = 0;
2750                         Normalise(&relative);
2751                         relative = DoRotation(relative, 0, 90, 0);
2752                         relative.y -= 1;
2753                         Normalise(&relative);
2754                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2755                             victim->skeleton.joints[i].velocity += relative * damagemult * 60;
2756                         }
2757                         victim->jointVel(head) += relative * damagemult * 230;
2758                         victim->jointVel(neck) += relative * damagemult * 230;
2759                         //FootLand(1,2);
2760                         victim->Puff(head);
2761                         if (tutoriallevel != 1) {
2762                             victim->DoDamage(damagemult * 120 / victim->protectionhigh);
2763
2764                             award_bonus(id, solidhit, 30);
2765                         }
2766                     }
2767                 }
2768
2769                 if (animTarget == staffspinhitanim && animation[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
2770                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
2771                         if (tutoriallevel != 1) {
2772                             weapons[weaponids[0]].damage += .6 + float(abs(Random() % 100) - 50) / 250;
2773                             escapednum = 0;
2774                             if (id == 0)
2775                                 camerashake += .4;
2776                             if (Random() % 2 || creature == wolftype) {
2777                                 victim->spurt = 1;
2778                             }
2779                             emit_sound_at(staffheadsound, victim->coords);
2780                         }
2781                         victim->RagDoll(0);
2782                         XYZ relative;
2783                         relative = victim->coords - coords;
2784                         relative.y = 0;
2785                         Normalise(&relative);
2786                         relative = DoRotation(relative, 0, -90, 0);
2787                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2788                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2789                         }
2790                         victim->jointVel(head) += relative * damagemult * 220;
2791                         victim->jointVel(neck) += relative * damagemult * 220;
2792                         //FootLand(1,2);
2793                         victim->Puff(head);
2794                         if (tutoriallevel != 1) {
2795                             victim->DoDamage(damagemult * 350 / victim->protectionhead);
2796
2797                             award_bonus(id, solidhit, 60);
2798                         }
2799                     }
2800                 }
2801
2802                 if (animTarget == staffgroundsmashanim && animation[animTarget].label[frameCurrent] == 5) {
2803                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5) {
2804                         escapednum = 0;
2805                         if (tutoriallevel != 1) {
2806                             if (!victim->dead)
2807                                 weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 500;
2808                             if (id == 0)
2809                                 camerashake += .4;
2810                             if (Random() % 2 || creature == wolftype) {
2811                                 victim->spurt = 1;
2812                             }
2813                             emit_sound_at(staffbodysound, victim->coords);
2814                         }
2815                         victim->skeleton.longdead = 0;
2816                         victim->skeleton.free = 1;
2817                         victim->skeleton.broken = 0;
2818
2819                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
2820                             victim->skeleton.joints[i].velchange = 0;
2821                             victim->skeleton.joints[i].locked = 0;
2822                             //victim->skeleton.joints[i].velocity=0;
2823                         }
2824
2825                         victim->RagDoll(0);
2826                         XYZ relative;
2827                         relative = 0;
2828                         /*relative=victim->coords-coords;
2829                         relative.y=0;
2830                         Normalise(&relative);
2831                         relative=DoRotation(relative,0,90,0);*/
2832                         relative.y = -1;
2833                         Normalise(&relative);
2834                         if (!victim->dead) {
2835                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2836                                 victim->skeleton.joints[i].velocity = relative * damagemult * 40;
2837                             }
2838                             //FootLand(1,2);
2839                             victim->jointVel(abdomen) += relative * damagemult * 40;
2840                         }
2841                         if (victim->dead) {
2842                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2843                                 victim->skeleton.joints[i].velocity = relative * damagemult * abs(Random() % 20);
2844                             }
2845                             //FootLand(1,2);
2846                             //victim->jointVel(abdomen)+=relative*damagemult*20;
2847                         }
2848                         victim->Puff(abdomen);
2849                         if (tutoriallevel != 1) {
2850                             victim->DoDamage(damagemult * 100 / victim->protectionhigh);
2851
2852                             if (!victim->dead) {
2853                                 award_bonus(id, solidhit, 40);
2854                             }
2855                         }
2856                     }
2857                 }
2858
2859                 if (animTarget == lowkickanim && animation[animTarget].label[frameCurrent] == 5) {
2860                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != highheight) {
2861                         escapednum = 0;
2862                         if (id == 0)
2863                             camerashake += .4;
2864                         XYZ relative;
2865                         relative = victim->coords - coords;
2866                         relative.y = 0;
2867                         Normalise(&relative);
2868
2869                         SolidHitBonus(id);
2870
2871                         if (animation[victim->animTarget].height == lowheight) {
2872                             if (Random() % 2) {
2873                                 victim->spurt = 1;
2874                                 DoBlood(.2, 250);
2875                             }
2876                             victim->RagDoll(0);
2877                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2878                                 victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2879                             }
2880                             victim->jointVel(head) += relative * damagemult * 200;
2881                             if (tutoriallevel != 1) {
2882                                 emit_sound_at(heavyimpactsound, victim->coords, 128.);
2883                             }
2884                             victim->Puff(head);
2885                             victim->DoDamage(damagemult * 100 / victim->protectionhead);
2886                             if (victim->howactive == typesleeping)
2887                                 victim->DoDamage(damagemult * 150 / victim->protectionhead);
2888                             if (creature == wolftype) {
2889                                 emit_sound_at(clawslicesound, victim->coords, 128.);
2890                                 victim->spurt = 1;
2891                                 victim->DoBloodBig(2 / victim->armorhead, 175);
2892                             }
2893                         } else {
2894                             if (victim->damage >= victim->damagetolerance)
2895                                 victim->RagDoll(0);
2896                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2897                                 victim->skeleton.joints[i].velocity += relative * damagemult * 10;
2898                             }
2899                             victim->jointVel(abdomen) += relative * damagemult * 200;
2900                             victim->frameTarget = 0;
2901                             victim->animTarget = staggerbackhighanim;
2902                             victim->targetyaw = targetyaw + 180;
2903                             victim->target = 0;
2904                             if (tutoriallevel != 1) {
2905                                 emit_sound_at(landsound2, victim->coords, 128.);
2906                             }
2907                             victim->Puff(abdomen);
2908                             victim->DoDamage(damagemult * 30 / victim->protectionhigh);
2909                             if (creature == wolftype) {
2910                                 emit_sound_at(clawslicesound, victim->coords, 128.);
2911                                 victim->spurt = 1;
2912                                 victim->DoBloodBig(2 / victim->armorhigh, 170);
2913                             }
2914                         }
2915
2916                     }
2917                 }
2918
2919                 if (animTarget == sweepanim && animation[animTarget].label[frameCurrent] == 5) {
2920                     if ((victim->animTarget != jumpupanim) &&
2921                         (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) &&
2922                         (victim != this->shared_from_this())) {
2923                         escapednum = 0;
2924                         if (id == 0)
2925                             camerashake += .2;
2926                         if (tutoriallevel != 1) {
2927                             emit_sound_at(landsound2, victim->coords, 128.);
2928                         }
2929                         XYZ relative;
2930                         relative = victim->coords - coords;
2931                         relative.y = 0;
2932                         Normalise(&relative);
2933
2934                         if (animation[victim->animTarget].height == middleheight || animation[victim->animCurrent].height == middleheight || victim->damage >= victim->damagetolerance - 40) {
2935                             victim->RagDoll(0);
2936
2937                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2938                                 victim->skeleton.joints[i].velocity += relative * damagemult * 15;
2939                             }
2940                             relative = DoRotation(relative, 0, -90, 0);
2941                             relative.y += .1;
2942                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2943                                 if (victim->skeleton.joints[i].label == leftfoot || victim->skeleton.joints[i].label == rightfoot || victim->skeleton.joints[i].label == leftankle || victim->skeleton.joints[i].label == rightankle)
2944                                     victim->skeleton.joints[i].velocity = relative * 80;
2945                             }
2946                             victim->Puff(rightankle);
2947                             victim->Puff(leftankle);
2948                             victim->DoDamage(damagemult * 40 / victim->protectionlow);
2949                         } else {
2950                             if (victim->damage >= victim->damagetolerance)
2951                                 victim->RagDoll(0);
2952                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2953                                 victim->skeleton.joints[i].velocity += relative * damagemult * 10;
2954                             }
2955                             relative = DoRotation(relative, 0, -90, 0);
2956                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
2957                                 if (victim->skeleton.joints[i].label == leftfoot || victim->skeleton.joints[i].label == rightfoot || victim->skeleton.joints[i].label == leftankle || victim->skeleton.joints[i].label == rightankle)
2958                                     victim->skeleton.joints[i].velocity += relative * damagemult * 80;
2959                             }
2960                             victim->jointVel(abdomen) += relative * damagemult * 200;
2961                             victim->frameTarget = 0;
2962                             victim->animTarget = staggerbackhighanim;
2963                             victim->targetyaw = targetyaw + 180;
2964                             victim->target = 0;
2965                             if (tutoriallevel != 1) {
2966                                 emit_sound_at(landsound2, victim->coords, 128.);
2967                             }
2968                             victim->Puff(abdomen);
2969                             victim->DoDamage(damagemult * 30 / victim->protectionlow);
2970                         }
2971
2972                         SolidHitBonus(id);
2973
2974                     }
2975                 }
2976             }
2977             if (animation[animTarget].attack == reversal && (!victim->feint || (victim->lastattack == victim->lastattack2 && victim->lastattack2 == victim->lastattack3 && Random() % 2) || animTarget == knifefollowanim)) {
2978                 if (animTarget == spinkickreversalanim && animation[animTarget].label[frameCurrent] == 7) {
2979                     escapednum = 0;
2980                     if (id == 0)
2981                         camerashake += .4;
2982                     if (Random() % 2) {
2983                         victim->spurt = 1;
2984                         DoBlood(.2, 230);
2985                     }
2986                     if (tutoriallevel != 1) {
2987                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
2988                     }
2989                     if (creature == wolftype) {
2990                         emit_sound_at(clawslicesound, victim->coords, 128);
2991                         victim->spurt = 1;
2992                         victim->DoBloodBig(2 / victim->armorhigh, 170);
2993                     }
2994                     victim->RagDoll(0);
2995                     XYZ relative;
2996                     relative = victim->coords - oldcoords;
2997                     relative.y = 0;
2998                     Normalise(&relative);
2999                     //relative=DoRotation(relative,0,-90,0);
3000                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3001                         victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3002                     }
3003                     victim->jointVel(abdomen) += relative * damagemult * 200;
3004                     //FootLand(1,2);
3005                     victim->Puff(abdomen);
3006                     victim->DoDamage(damagemult * 150 / victim->protectionhigh);
3007
3008                     award_bonus(id, Reversal);
3009                 }
3010
3011                 if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && animation[animTarget].label[frameCurrent] == 5) {
3012                     if (victim->weaponactive != -1 && victim->num_weapons > 0) {
3013                         if (weapons[victim->weaponids[victim->weaponactive]].owner == int(victim->id)) {
3014                             takeWeapon(victim->weaponids[victim->weaponactive]);
3015                             victim->num_weapons--;
3016                             if (victim->num_weapons > 0) {
3017                                 victim->weaponids[victim->weaponactive] = victim->weaponids[victim->num_weapons];
3018                             }
3019                             victim->weaponactive = -1;
3020                         }
3021                     }
3022                 }
3023
3024                 if (animTarget == staffhitreversalanim && animation[animTarget].label[frameCurrent] == 5) {
3025                     escapednum = 0;
3026                     if (id == 0)
3027                         camerashake += .4;
3028                     if (Random() % 2) {
3029                         victim->spurt = 1;
3030                         DoBlood(.2, 230);
3031                     }
3032                     emit_sound_at(whooshhitsound, victim->coords, 128.);
3033                     victim->RagDoll(0);
3034                     XYZ relative;
3035                     relative = victim->coords - oldcoords;
3036                     relative.y = 0;
3037                     Normalise(&relative);
3038                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3039                         victim->skeleton.joints[i].velocity += relative * damagemult * 30;
3040                     }
3041                     victim->jointVel(abdomen) += relative * damagemult * 200;
3042                     victim->Puff(head);
3043                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
3044                 }
3045
3046                 if (animTarget == staffspinhitreversalanim && animation[animTarget].label[frameCurrent] == 7) {
3047                     escapednum = 0;
3048                     if (id == 0)
3049                         camerashake += .4;
3050                     if (Random() % 2) {
3051                         victim->spurt = 1;
3052                         DoBlood(.2, 230);
3053                     }
3054
3055                     award_bonus(id, staffreversebonus);
3056
3057                     if (tutoriallevel != 1) {
3058                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
3059                     }
3060                     victim->RagDoll(0);
3061                     award_bonus(id, staffreversebonus); // Huh, again?
3062
3063                     XYZ relative;
3064                     relative = victim->coords - oldcoords;
3065                     relative.y = 0;
3066                     Normalise(&relative);
3067                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3068                         victim->skeleton.joints[i].velocity += relative * damagemult * 30;
3069                     }
3070                     victim->jointVel(abdomen) += relative * damagemult * 200;
3071                     victim->Puff(head);
3072                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
3073                 }
3074
3075                 if (animTarget == upunchreversalanim && animation[animTarget].label[frameCurrent] == 7) {
3076                     escapednum = 0;
3077                     victim->RagDoll(1);
3078                     XYZ relative;
3079                     relative = facing;
3080                     relative.y = 0;
3081                     Normalise(&relative);
3082                     relative.y -= .1;
3083                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3084                         victim->skeleton.joints[i].velocity += relative * damagemult * 70;
3085                     }
3086                     victim->jointVel(lefthand) *= .1;
3087                     victim->jointVel(leftwrist) *= .2;
3088                     victim->jointVel(leftelbow) *= .5;
3089                     victim->jointVel(leftshoulder) *= .7;
3090                     victim->jointVel(righthand) *= .1;
3091                     victim->jointVel(rightwrist) *= .2;
3092                     victim->jointVel(rightelbow) *= .5;
3093                     victim->jointVel(rightshoulder) *= .7;
3094
3095                     victim->Puff(abdomen);
3096                     victim->DoDamage(damagemult * 90 / victim->protectionhigh);
3097
3098                     award_bonus(id, Reversal);
3099
3100                     bool doslice;
3101                     doslice = 0;
3102                     if (weaponactive != -1 || creature == wolftype)
3103                         doslice = 1;
3104                     if (creature == rabbittype && weaponactive != -1)
3105                         if (weapons[weaponids[0]].getType() == staff)
3106                             doslice = 0;
3107                     if (doslice) {
3108                         if (weaponactive != -1) {
3109                             victim->DoBloodBig(2 / victim->armorhigh, 225);
3110                             emit_sound_at(knifeslicesound, victim->coords);
3111                             if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
3112                                 weapons[weaponids[weaponactive]].bloody = 1;
3113                             weapons[weaponids[weaponactive]].blooddrip += 3;
3114                         }
3115                         if (weaponactive == -1 && creature == wolftype) {
3116                             ;
3117                             emit_sound_at(clawslicesound, victim->coords, 128.);
3118                             victim->spurt = 1;
3119                             victim->DoBloodBig(2 / victim->armorhigh, 175);
3120                         }
3121                     }
3122                 }
3123
3124
3125
3126                 if (animTarget == swordslashreversalanim && animation[animTarget].label[frameCurrent] == 7) {
3127                     escapednum = 0;
3128                     victim->RagDoll(1);
3129                     XYZ relative;
3130                     relative = facing;
3131                     relative.y = 0;
3132                     Normalise(&relative);
3133                     relative.y -= .1;
3134                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3135                         victim->skeleton.joints[i].velocity += relative * damagemult * 70;
3136                     }
3137                     victim->jointVel(lefthand) *= .1 - 1;
3138                     victim->jointVel(leftwrist) *= .2 - 1;
3139                     victim->jointVel(leftelbow) *= .5 - 1;
3140                     victim->jointVel(leftshoulder) *= .7 - 1;
3141                     victim->jointVel(righthand) *= .1 - 1;
3142                     victim->jointVel(rightwrist) *= .2 - 1;
3143                     victim->jointVel(rightelbow) *= .5 - 1;
3144                     victim->jointVel(rightshoulder) *= .7 - 1;
3145
3146                     award_bonus(id, swordreversebonus);
3147                 }
3148
3149                 if (hasvictim && animTarget == knifeslashreversalanim && animation[animTarget].label[frameCurrent] == 7) {
3150                     escapednum = 0;
3151                     if (id == 0)
3152                         camerashake += .4;
3153                     if (Random() % 2) {
3154                         victim->spurt = 1;
3155                         DoBlood(.2, 230);
3156                     }
3157                     if (tutoriallevel != 1) {
3158                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
3159                     }
3160                     victim->RagDoll(0);
3161                     XYZ relative;
3162                     relative = victim->coords - oldcoords;
3163                     relative.y = 0;
3164                     Normalise(&relative);
3165                     relative = DoRotation(relative, 0, -90, 0);
3166                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3167                         victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3168                     }
3169                     victim->jointVel(abdomen) += relative * damagemult * 200;
3170                     victim->Puff(abdomen);
3171                     victim->DoDamage(damagemult * 30 / victim->protectionhigh);
3172
3173                     award_bonus(id, Reversal);
3174                 }
3175
3176                 if (hasvictim && animTarget == sneakattackanim && animation[animTarget].label[frameCurrent] == 7) {
3177                     escapednum = 0;
3178                     victim->RagDoll(0);
3179                     victim->skeleton.spinny = 0;
3180                     XYZ relative;
3181                     relative = facing * -1;
3182                     relative.y = -3;
3183                     Normalise(&relative);
3184                     if (victim->id == 0)
3185                         relative /= 30;
3186                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3187                         victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3188                     }
3189                     victim->damage = victim->damagetolerance;
3190                     victim->permanentdamage = victim->damagetolerance - 1;
3191                     bool doslice;
3192                     doslice = 0;
3193                     if (weaponactive != -1 || creature == wolftype)
3194                         doslice = 1;
3195                     if (creature == rabbittype && weaponactive != -1)
3196                         if (weapons[weaponids[0]].getType() == staff)
3197                             doslice = 0;
3198                     if (doslice) {
3199                         if (weaponactive != -1) {
3200                             victim->DoBloodBig(200, 225);
3201                             emit_sound_at(knifeslicesound, victim->coords);
3202                             if (bloodtoggle)
3203                                 weapons[weaponids[weaponactive]].bloody = 2;
3204                             weapons[weaponids[weaponactive]].blooddrip += 5;
3205                         }
3206
3207                         if (creature == wolftype && weaponactive == -1) {
3208                             emit_sound_at(clawslicesound, victim->coords, 128.);
3209                             victim->spurt = 1;
3210                             victim->DoBloodBig(2, 175);
3211                         }
3212                     }
3213                     award_bonus(id, spinecrusher);
3214                 }
3215
3216                 if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && animation[animTarget].label[frameCurrent] == 5) {
3217                     if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
3218                         escapednum = 0;
3219                         if (animTarget == knifefollowanim)
3220                             victim->DoBloodBig(200, 210);
3221                         if (animTarget == knifesneakattackanim) {
3222                             XYZ footvel, footpoint;
3223                             footvel = 0;
3224                             footpoint = weapons[weaponids[0]].tippoint;
3225                             if (bloodtoggle)
3226                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3227                             footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
3228                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3229                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3230                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3231                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3232                             victim->DoBloodBig(200, 195);
3233                             award_bonus(id, tracheotomy);
3234                         }
3235                         if (animTarget == knifefollowanim) {
3236                             award_bonus(id, Stabbonus);
3237                             XYZ footvel, footpoint;
3238                             footvel = 0;
3239                             footpoint = weapons[weaponids[0]].tippoint;
3240                             if (bloodtoggle)
3241                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3242                             footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
3243                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3244                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3245                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
3246                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
3247
3248                         }
3249                         victim->bloodloss += 10000;
3250                         victim->velocity = 0;
3251                         emit_sound_at(fleshstabsound, victim->coords);
3252                         if (bloodtoggle)
3253                             weapons[weaponids[weaponactive]].bloody = 2;
3254                         weapons[weaponids[weaponactive]].blooddrip += 5;
3255                     }
3256                 }
3257
3258                 if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && animation[animTarget].label[frameCurrent] == 6) {
3259                     escapednum = 0;
3260                     victim->velocity = 0;
3261                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3262                         victim->skeleton.joints[i].velocity = 0;
3263                     }
3264                     if (animTarget == knifefollowanim) {
3265                         victim->RagDoll(0);
3266                         for (int i = 0; i < victim->skeleton.num_joints; i++) {
3267                             victim->skeleton.joints[i].velocity = 0;
3268                         }
3269                     }
3270                     if (weaponactive != -1 && animation[victim->animTarget].attack != reversal) {
3271                         emit_sound_at(fleshstabremovesound, victim->coords);
3272                         if (bloodtoggle)
3273                             weapons[weaponids[weaponactive]].bloody = 2;
3274                         weapons[weaponids[weaponactive]].blooddrip += 5;
3275
3276                         XYZ footvel, footpoint;
3277                         footvel = 0;
3278                         footpoint = weapons[weaponids[0]].tippoint;
3279                         if (bloodtoggle)
3280                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3281                         footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
3282                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3283                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3284                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3285                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3286                     }
3287                 }
3288
3289                 if (hasvictim && (animTarget == swordsneakattackanim) && animation[animTarget].label[frameCurrent] == 5) {
3290                     if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
3291                         award_bonus(id, backstab);
3292
3293                         escapednum = 0;
3294
3295                         XYZ footvel, footpoint;
3296                         footvel = 0;
3297                         footpoint = (weapons[weaponids[0]].tippoint + weapons[weaponids[0]].position) / 2;
3298                         if (bloodtoggle)
3299                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3300                         footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
3301                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3302                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3303                         Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 5, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
3304                         Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
3305                         victim->DoBloodBig(200, 180);
3306                         victim->DoBloodBig(200, 215);
3307                         victim->bloodloss += 10000;
3308                         victim->velocity = 0;
3309                         emit_sound_at(fleshstabsound, victim->coords);
3310                         if (bloodtoggle)
3311                             weapons[weaponids[weaponactive]].bloody = 2;
3312                         weapons[weaponids[weaponactive]].blooddrip += 5;
3313                     }
3314                 }
3315
3316                 if (hasvictim && animTarget == swordsneakattackanim && animation[animTarget].label[frameCurrent] == 6) {
3317                     escapednum = 0;
3318                     victim->velocity = 0;
3319                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3320                         victim->skeleton.joints[i].velocity = 0;
3321                     }
3322                     if (weaponactive != -1) {
3323                         emit_sound_at(fleshstabremovesound, victim->coords);
3324                         if (bloodtoggle)
3325                             weapons[weaponids[weaponactive]].bloody = 2;
3326                         weapons[weaponids[weaponactive]].blooddrip += 5;
3327
3328                         XYZ footvel, footpoint;
3329                         footvel = 0;
3330                         footpoint = weapons[weaponids[0]].tippoint;
3331                         if (bloodtoggle)
3332                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3333                         footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
3334                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3335                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3336                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3337                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3338                     }
3339                 }
3340
3341                 if (animTarget == sweepreversalanim && animation[animTarget].label[frameCurrent] == 7) {
3342                     escapednum = 0;
3343                     if (id == 0)
3344                         camerashake += .4;
3345                     if (Random() % 2) {
3346                         victim->spurt = 1;
3347                         DoBlood(.2, 240);
3348                     }
3349                     if (weaponactive == -1) {
3350                         if (tutoriallevel != 1) {
3351                             emit_sound_at(heavyimpactsound, victim->coords, 128.);
3352                         }
3353                     }
3354                     bool doslice;
3355                     doslice = 0;
3356                     if (weaponactive != -1 || creature == wolftype)
3357                         doslice = 1;
3358                     if (creature == rabbittype && weaponactive != -1)
3359                         if (weapons[weaponids[0]].getType() == staff)
3360                             doslice = 0;
3361                     if (doslice) {
3362                         if (weaponactive != -1) {
3363                             victim->DoBloodBig(2 / victim->armorhead, 225);
3364                             emit_sound_at(knifeslicesound, victim->coords);
3365                             if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
3366                                 weapons[weaponids[weaponactive]].bloody = 1;
3367                             weapons[weaponids[weaponactive]].blooddrip += 3;
3368                         }
3369                         if (weaponactive == -1 && creature == wolftype) {
3370                             emit_sound_at(clawslicesound, victim->coords, 128.);
3371                             victim->spurt = 1;
3372                             victim->DoBloodBig(2 / victim->armorhead, 175);
3373                         }
3374                     }
3375
3376                     award_bonus(id, Reversal);
3377
3378                     victim->Puff(neck);
3379
3380                     XYZ relative;
3381                     relative = facing * -1;
3382                     relative.y = 0;
3383                     Normalise(&relative);
3384                     relative = DoRotation(relative, 0, 90, 0);
3385                     relative.y = .5;
3386                     Normalise(&relative);
3387                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3388                         victim->skeleton.joints[i].velocity += relative * damagemult * 20;
3389                     }
3390                     victim->jointVel(head) += relative * damagemult * 200;
3391                     if (victim->damage < victim->damagetolerance - 100)
3392                         victim->velocity = relative * 200;
3393                     victim->DoDamage(damagemult * 100 / victim->protectionhead);
3394                     victim->velocity = 0;
3395                 }
3396
3397                 if (animTarget == sweepreversalanim && ((animation[animTarget].label[frameCurrent] == 9 && victim->damage < victim->damagetolerance) || (animation[animTarget].label[frameCurrent] == 7 && victim->damage > victim->damagetolerance))) {
3398                     escapednum = 0;
3399                     victim->RagDoll(0);
3400                     XYZ relative;
3401                     relative = facing * -1;
3402                     relative.y = 0;
3403                     Normalise(&relative);
3404                     relative = DoRotation(relative, 0, 90, 0);
3405                     relative.y = .5;
3406                     Normalise(&relative);
3407                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
3408                         victim->skeleton.joints[i].velocity += relative * damagemult * 20;
3409                     }
3410                     victim->jointVel(head) += relative * damagemult * 200;
3411                 }
3412
3413                 if (hasvictim && (animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == rabbitkickreversalanim || animTarget == upunchreversalanim || animTarget == jumpreversalanim || animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == rabbittacklereversal || animTarget == wolftacklereversal || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim))
3414                     if (victim->damage > victim->damagetolerance && bonus != reverseko) {
3415                         award_bonus(id, reverseko);
3416                     }
3417             }
3418
3419
3420             //Animation end
3421             if (frameTarget > animation[animCurrent].numframes - 1) {
3422                 frameTarget = 0;
3423                 if (wasStop()) {
3424                     animTarget = getIdle();
3425                     FootLand(0, 1);
3426                     FootLand(1, 1);
3427                 }
3428                 if (animCurrent == rabbittackleanim || animCurrent == rabbittacklinganim) {
3429                     animTarget = rollanim;
3430                     frameTarget = 3;
3431                     emit_sound_at(movewhooshsound, coords, 128.);
3432                 }
3433                 if (animCurrent == staggerbackhighanim) {
3434                     animTarget = getIdle();
3435                 }
3436                 if (animCurrent == staggerbackhardanim) {
3437                     animTarget = getIdle();
3438                 }
3439                 if (animCurrent == removeknifeanim) {
3440                     animTarget = getIdle();
3441                 }
3442                 if (animCurrent == crouchremoveknifeanim) {
3443                     animTarget = getCrouch();
3444                 }
3445                 if (animCurrent == backhandspringanim) {
3446                     animTarget = getIdle();
3447                 }
3448                 if (animCurrent == dodgebackanim) {
3449                     animTarget = getIdle();
3450                 }
3451                 if (animCurrent == drawleftanim) {
3452                     animTarget = getIdle();
3453                 }
3454                 if (animCurrent == drawrightanim || animCurrent == crouchdrawrightanim) {
3455                     animTarget = getIdle();
3456                     if (animCurrent == crouchdrawrightanim) {
3457                         animTarget = getCrouch();
3458                     }
3459                     if (weaponactive == -1)
3460                         weaponactive = 0;
3461                     else if (weaponactive == 0) {
3462                         weaponactive = -1;
3463                         if (num_weapons == 2) {
3464                             int buffer;
3465                             buffer = weaponids[0];
3466                             weaponids[0] = weaponids[1];
3467                             weaponids[1] = buffer;
3468                         }
3469                     }
3470
3471                     if (weaponactive == -1) {
3472                         emit_sound_at(knifesheathesound, coords, 128.);
3473                     }
3474                     if (weaponactive != -1) {
3475                         emit_sound_at(knifedrawsound, coords, 128.);
3476                     }
3477                 }
3478                 if (animCurrent == rollanim) {
3479                     animTarget = getCrouch();
3480                     FootLand(0, 1);
3481                     FootLand(1, 1);
3482                 }
3483                 if (isFlip()) {
3484                     if (animTarget == walljumprightkickanim) {
3485                         targetrot = -190;
3486                     }
3487                     if (animTarget == walljumpleftkickanim) {
3488                         targetrot = 190;
3489                     }
3490                     animTarget = jumpdownanim;
3491                 }
3492                 if (animCurrent == climbanim) {
3493                     animTarget = getCrouch();
3494                     frameTarget = 1;
3495                     coords += facing * .1;
3496                     if (!isnormal(coords.x))
3497                         coords = oldcoords;
3498                     oldcoords = coords;
3499                     collided = 0;
3500                     targetoffset = 0;
3501                     currentoffset = 0;
3502                     grabdelay = 1;
3503                     velocity = 0;
3504                     collided = 0;
3505                     avoidcollided = 0;
3506                 }
3507                 if (animTarget == rabbitkickreversalanim) {
3508                     animTarget = getCrouch();
3509                     lastfeint = 0;
3510                 }
3511                 if (animTarget == jumpreversalanim) {
3512                     animTarget = getCrouch();
3513                     lastfeint = 0;
3514                 }
3515                 if (animTarget == walljumprightanim || animTarget == walljumpbackanim || animTarget == walljumpfrontanim) {
3516                     if (attackkeydown && animTarget != walljumpfrontanim) {
3517                         int closest = -1;
3518                         float closestdist = -1;
3519                         float distance;
3520                         if (Person::players.size() > 1)
3521                             for (unsigned i = 0; i < Person::players.size(); i++) {
3522                                 if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
3523                                     distance = distsq(&Person::players[i]->coords, &coords);
3524                                     if (closestdist == -1 || distance < closestdist) {
3525                                         closestdist = distance;
3526                                         closest = i;
3527                                     }
3528                                 }
3529                             }
3530                         if (closestdist > 0 && closest >= 0 && closestdist < 16) {
3531                             victim = Person::players[closest];
3532                             animTarget = walljumprightkickanim;
3533                             frameTarget = 0;
3534                             XYZ rotatetarget = victim->coords - coords;
3535                             Normalise(&rotatetarget);
3536                             yaw = -asin(0 - rotatetarget.x);
3537                             yaw *= 360 / 6.28;
3538                             if (rotatetarget.z < 0)
3539                                 yaw = 180 - yaw;
3540                             targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
3541                             velocity = (victim->coords - coords) * 4;
3542                             velocity.y += 2;
3543                             transspeed = 40;
3544                         }
3545                     }
3546                     if (animTarget == walljumpbackanim) {
3547                         animTarget = backflipanim;
3548                         frameTarget = 3;
3549                         velocity = facing * -8;
3550                         velocity.y = 4;
3551                         if (id == 0)
3552                             resume_stream(whooshsound);
3553                     }
3554                     if (animTarget == walljumprightanim) {
3555                         animTarget = rightflipanim;
3556                         frameTarget = 4;
3557                         targetyaw -= 90;
3558                         yaw -= 90;
3559                         velocity = DoRotation(facing, 0, 30, 0) * -8;
3560                         velocity.y = 4;
3561                     }
3562                     if (animTarget == walljumpfrontanim) {
3563                         animTarget = frontflipanim;
3564                         frameTarget = 2;
3565                         //targetyaw-=180;
3566                         ////yaw-=180;
3567                         velocity = facing * 8;
3568                         velocity.y = 4;
3569                     }
3570                     if (id == 0)
3571                         resume_stream(whooshsound);
3572                 }
3573                 if (animTarget == walljumpleftanim) {
3574                     if (attackkeydown) {
3575                         int closest = -1;
3576                         float closestdist = -1;
3577                         float distance;
3578                         if (Person::players.size() > 1)
3579                             for (unsigned i = 0; i < Person::players.size(); i++) {
3580                                 if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
3581                                     distance = distsq(&Person::players[i]->coords, &coords);
3582                                     if (closestdist == -1 || distance < closestdist) {
3583                                         closestdist = distance;
3584                                         closest = i;
3585                                     }
3586                                 }
3587                             }
3588                         if (closestdist > 0 && closest >= 0 && closestdist < 16) {
3589                             victim = Person::players[closest];
3590                             animTarget = walljumpleftkickanim;
3591                             frameTarget = 0;
3592                             XYZ rotatetarget = victim->coords - coords;
3593                             Normalise(&rotatetarget);
3594                             yaw = -asin(0 - rotatetarget.x);
3595                             yaw *= 360 / 6.28;
3596                             if (rotatetarget.z < 0)
3597                                 yaw = 180 - yaw;
3598                             targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
3599                             velocity = (victim->coords - coords) * 4;
3600                             velocity.y += 2;
3601                             transspeed = 40;
3602                         }
3603                     }
3604                     if (animTarget != walljumpleftkickanim) {
3605                         animTarget = leftflipanim;
3606                         frameTarget = 4;
3607                         targetyaw += 90;
3608                         yaw += 90;
3609                         velocity = DoRotation(facing, 0, -30, 0) * -8;
3610                         velocity.y = 4;
3611                     }
3612                     if (id == 0)
3613                         resume_stream(whooshsound);
3614                 }
3615                 if (animTarget == sneakattackanim) {
3616                     animCurrent = getCrouch();
3617                     animTarget = getCrouch();
3618                     frameTarget = 1;
3619                     frameCurrent = 0;
3620                     targetyaw += 180;
3621                     yaw += 180;
3622                     targettilt2 *= -1;
3623                     tilt2 *= -1;
3624                     transspeed = 1000000;
3625                     targetheadyaw += 180;
3626                     coords -= facing * .7;
3627                     if (onterrain)
3628                         coords.y = terrain.getHeight(coords.x, coords.z);
3629
3630                     lastfeint = 0;
3631                 }
3632                 if (animTarget == knifesneakattackanim || animTarget == swordsneakattackanim) {
3633                     animTarget = getIdle();
3634                     frameTarget = 0;
3635                     if (onterrain)
3636                         coords.y = terrain.getHeight(coords.x, coords.z);
3637
3638                     lastfeint = 0;
3639                 }
3640                 if (animCurrent == knifefollowanim) {
3641                     animTarget = getIdle();
3642                     lastfeint = 0;
3643                 }
3644                 if (animation[animTarget].attack == reversal && animCurrent != sneakattackanim && animCurrent != knifesneakattackanim && animCurrent != swordsneakattackanim && animCurrent != knifefollowanim) {
3645                     float ycoords = oldcoords.y;
3646                     animTarget = getStop();
3647                     targetyaw += 180;
3648                     yaw += 180;
3649                     targettilt2 *= -1;
3650                     tilt2 *= -1;
3651                     transspeed = 1000000;
3652                     targetheadyaw += 180;
3653                     if (!isnormal(coords.x))
3654                         coords = oldcoords;
3655                     if (animCurrent == spinkickreversalanim || animCurrent == swordslashreversalanim)
3656                         oldcoords = coords + facing * .5;
3657                     else if (animCurrent == sweepreversalanim)
3658                         oldcoords = coords + facing * 1.1;
3659                     else if (animCurrent == upunchreversalanim) {
3660                         oldcoords = coords + facing * 1.5;
3661                         targetyaw += 180;
3662                         yaw += 180;
3663                         targetheadyaw += 180;
3664                         targettilt2 *= -1;
3665                         tilt2 *= -1;
3666                     } else if (animCurrent == knifeslashreversalanim) {
3667                         oldcoords = coords + facing * .5;
3668                         targetyaw += 90;
3669                         yaw += 90;
3670                         targetheadyaw += 90;
3671                         targettilt2 = 0;
3672                         tilt2 = 0;
3673                     } else if (animCurrent == staffspinhitreversalanim) {
3674                         targetyaw += 180;
3675                         yaw += 180;
3676                         targetheadyaw += 180;
3677                         targettilt2 = 0;
3678                         tilt2 = 0;
3679                     }
3680                     if (onterrain)
3681                         oldcoords.y = terrain.getHeight(oldcoords.x, oldcoords.z);
3682                     else
3683                         oldcoords.y = ycoords;
3684                     currentoffset = coords - oldcoords;
3685                     targetoffset = 0;
3686                     coords = oldcoords;
3687
3688                     lastfeint = 0;
3689                 }
3690                 if (animCurrent == knifesneakattackedanim || animCurrent == swordsneakattackedanim) {
3691                     velocity = 0;
3692                     velocity.y = -5;
3693                     RagDoll(0);
3694                 }
3695                 if (animation[animTarget].attack == reversed) {
3696                     escapednum++;
3697                     if (animTarget == sweepreversedanim)
3698                         targetyaw += 90;
3699                     animTarget = backhandspringanim;
3700                     frameTarget = 2;
3701                     emit_sound_at(landsound, coords, 128);
3702
3703                     if (animCurrent == upunchreversedanim || animCurrent == swordslashreversedanim) {
3704                         animTarget = rollanim;
3705                         frameTarget = 5;
3706                         oldcoords = coords;
3707                         coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
3708                         coords.y = oldcoords.y;
3709                     }
3710                     if (animCurrent == knifeslashreversedanim) {
3711                         animTarget = rollanim;
3712                         frameTarget = 0;
3713                         targetyaw += 90;
3714                         yaw += 90;
3715                         oldcoords = coords;
3716                         coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
3717                         coords.y = oldcoords.y;
3718                     }
3719                 }
3720                 if (wasFlip()) {
3721                     animTarget = jumpdownanim;
3722                 }
3723                 if (wasLanding())
3724                     animTarget = getIdle();
3725                 if (wasLandhard())
3726                     animTarget = getIdle();
3727                 if (animCurrent == spinkickanim || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == lowkickanim) {
3728                     animTarget = getIdle();
3729                     oldcoords = coords;
3730                     coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
3731                     coords.y = oldcoords.y;
3732                     //coords+=DoRotation(animation[animCurrent].offset,0,yaw,0)*scale;
3733                     targetoffset.y = coords.y;
3734                     if (onterrain)
3735                         targetoffset.y = terrain.getHeight(coords.x, coords.z);
3736                     currentoffset = DoRotation(animation[animCurrent].offset * -1, 0, yaw, 0) * scale;
3737                     currentoffset.y -= (coords.y - targetoffset.y);
3738                     coords.y = targetoffset.y;
3739                     targetoffset = 0;
3740                     normalsupdatedelay = 0;
3741                 }
3742                 if (animCurrent == upunchanim) {
3743                     animTarget = getStop();
3744                     normalsupdatedelay = 0;
3745                     lastfeint = 0;
3746                 }
3747                 if (animCurrent == rabbitkickanim && animTarget != backflipanim) {
3748                     targetyaw = yaw;
3749                     bool hasstaff;
3750                     hasstaff = 0;
3751                     if (num_weapons > 0)
3752                         if (weapons[0].getType() == staff)
3753                             hasstaff = 1;
3754                     if (!hasstaff)
3755                         DoDamage(35);
3756                     RagDoll(0);
3757                     lastfeint = 0;
3758                     rabbitkickragdoll = 1;
3759                 }
3760                 if (animCurrent == rabbitkickreversedanim) {
3761                     if (!feint) {
3762                         velocity = 0;
3763                         velocity.y = -10;
3764                         //DoDamage(100);
3765                         RagDoll(0);
3766                         skeleton.spinny = 0;
3767                         SolidHitBonus(!id); // FIXME: tricky id
3768                     }
3769                     if (feint) {
3770                         escapednum++;
3771                         animTarget = rollanim;
3772                         coords += facing;
3773                         if (id == 0)
3774                             pause_sound(whooshsound);
3775                     }
3776                     lastfeint = 0;
3777                 }
3778                 if (animCurrent == rabbittackledbackanim || animCurrent == rabbittackledfrontanim) {
3779                     velocity = 0;
3780                     velocity.y = -10;
3781                     RagDoll(0);
3782                     skeleton.spinny = 0;
3783                 }
3784                 if (animCurrent == jumpreversedanim) {
3785                     if (!feint) {
3786                         velocity = 0;
3787                         velocity.y = -10;
3788                         //DoDamage(100);
3789                         RagDoll(0);
3790                         skeleton.spinny = 0;
3791                         SolidHitBonus(!id); // FIXME: tricky id
3792                     }
3793                     if (feint) {
3794                         escapednum++;
3795                         animTarget = rollanim;
3796                         coords += facing * 2;
3797                         if (id == 0)
3798                             pause_sound(whooshsound);
3799                     }
3800                     lastfeint = 0;
3801                 }
3802
3803                 if (animation[animCurrent].attack == normalattack && !victim->skeleton.free && victim->animTarget != staggerbackhighanim && victim->animTarget != staggerbackhardanim && animTarget != winduppunchblockedanim && animTarget != blockhighleftanim && animTarget != swordslashparryanim && animTarget != swordslashparriedanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim) {
3804                     animTarget = getupfromfrontanim;
3805                     lastfeint = 0;
3806                 } else if (animation[animCurrent].attack == normalattack) {
3807                     animTarget = getIdle();
3808                     lastfeint = 0;
3809                 }
3810                 if (animCurrent == blockhighleftanim && aitype != playercontrolled) {
3811                     animTarget = blockhighleftstrikeanim;
3812                 }
3813                 if (animCurrent == knifeslashstartanim || animCurrent == knifethrowanim || animCurrent == swordslashanim || animCurrent == staffhitanim || animCurrent == staffgroundsmashanim || animCurrent == staffspinhitanim) {
3814                     animTarget = getIdle();
3815                     lastfeint = 0;
3816                 }
3817                 if (animCurrent == spinkickanim && victim->skeleton.free) {
3818                     if (creature == rabbittype)
3819                         animTarget = fightidleanim;
3820                 }
3821             }
3822             target = 0;
3823
3824             if (isIdle() && !wasIdle())
3825                 normalsupdatedelay = 0;
3826
3827             if (animCurrent == jumpupanim && velocity.y < 0 && !isFlip()) {
3828                 animTarget = jumpdownanim;
3829             }
3830         }
3831         if (!skeleton.free) {
3832             oldtarget = target;
3833             if (!transspeed && animation[animTarget].attack != 2 && animation[animTarget].attack != 3) {
3834                 if (!isRun() || !wasRun()) {
3835                     if (animation[animTarget].speed[frameTarget] > animation[animCurrent].speed[frameCurrent])
3836                         target += multiplier * animation[animTarget].speed[frameTarget] * speed * 2;
3837                     if (animation[animTarget].speed[frameTarget] <= animation[animCurrent].speed[frameCurrent])
3838                         target += multiplier * animation[animCurrent].speed[frameCurrent] * speed * 2;
3839                 }
3840                 if (isRun() && wasRun()) {
3841                     float tempspeed;
3842                     tempspeed = velspeed;
3843                     if (tempspeed < 10 * speedmult)
3844                         tempspeed = 10 * speedmult;
3845                     target += multiplier * animation[animTarget].speed[frameCurrent] * speed * 1.7 * tempspeed / (speed * 45 * scale);
3846                 }
3847             } else if (transspeed)
3848                 target += multiplier * transspeed * speed * 2;
3849             else {
3850                 if (!isRun() || !wasRun()) {
3851                     if (animation[animTarget].speed[frameTarget] > animation[animCurrent].speed[frameCurrent])
3852                         target += multiplier * animation[animTarget].speed[frameTarget] * 2;
3853                     if (animation[animTarget].speed[frameTarget] <= animation[animCurrent].speed[frameCurrent])
3854                         target += multiplier * animation[animCurrent].speed[frameCurrent] * 2;
3855                 }
3856             }
3857
3858             if (animCurrent != animTarget)
3859                 target = (target + oldtarget) / 2;
3860
3861             if (target > 1) {
3862                 frameCurrent = frameTarget;
3863                 target = 1;
3864             }
3865             oldrot = rot;
3866             rot = targetrot * target;
3867             yaw += rot - oldrot;
3868             if (target == 1) {
3869                 rot = 0;
3870                 oldrot = 0;
3871                 targetrot = 0;
3872             }
3873             if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
3874                 //Old rotates
3875                 for (int i = 0; i < skeleton.num_joints; i++) {
3876                     skeleton.joints[i].position = animation[animCurrent].position[i][frameCurrent];
3877                 }
3878
3879                 skeleton.FindForwards();
3880
3881                 for (int i = 0; i < skeleton.num_muscles; i++) {
3882                     if (skeleton.muscles[i].visible) {
3883                         skeleton.FindRotationMuscle(i, animTarget);
3884                     }
3885                 }
3886                 for (int i = 0; i < skeleton.num_muscles; i++) {
3887                     if (skeleton.muscles[i].visible) {
3888                         if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100))
3889                             skeleton.muscles[i].oldrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
3890                         if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100))
3891                             skeleton.muscles[i].oldrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
3892                         if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100))
3893                             skeleton.muscles[i].oldrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
3894                     }
3895                 }
3896
3897                 //New rotates
3898                 for (int i = 0; i < skeleton.num_joints; i++) {
3899                     skeleton.joints[i].position = animation[animTarget].position[i][frameTarget];
3900                 }
3901
3902                 skeleton.FindForwards();
3903
3904                 for (int i = 0; i < skeleton.num_muscles; i++) {
3905                     if (skeleton.muscles[i].visible) {
3906                         skeleton.FindRotationMuscle(i, animTarget);
3907                     }
3908                 }
3909                 for (int i = 0; i < skeleton.num_muscles; i++) {
3910                     if (skeleton.muscles[i].visible) {
3911                         if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100))
3912                             skeleton.muscles[i].newrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
3913                         if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100))
3914                             skeleton.muscles[i].newrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
3915                         if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100))
3916                             skeleton.muscles[i].newrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
3917                         if (skeleton.muscles[i].newrotate3 > skeleton.muscles[i].oldrotate3 + 180) skeleton.muscles[i].newrotate3 -= 360;
3918                         if (skeleton.muscles[i].newrotate3 < skeleton.muscles[i].oldrotate3 - 180) skeleton.muscles[i].newrotate3 += 360;
3919                         if (skeleton.muscles[i].newrotate2 > skeleton.muscles[i].oldrotate2 + 180) skeleton.muscles[i].newrotate2 -= 360;
3920                         if (skeleton.muscles[i].newrotate2 < skeleton.muscles[i].oldrotate2 - 180) skeleton.muscles[i].newrotate2 += 360;
3921                         if (skeleton.muscles[i].newrotate1 > skeleton.muscles[i].oldrotate1 + 180) skeleton.muscles[i].newrotate1 -= 360;
3922                         if (skeleton.muscles[i].newrotate1 < skeleton.muscles[i].oldrotate1 - 180) skeleton.muscles[i].newrotate1 += 360;
3923                     }
3924                 }
3925             }
3926             if (frameCurrent >= animation[animCurrent].numframes)
3927                 frameCurrent = animation[animCurrent].numframes - 1;
3928
3929             oldanimCurrent = animCurrent;
3930             oldanimTarget = animTarget;
3931             oldframeTarget = frameTarget;
3932             oldframeCurrent = frameCurrent;
3933
3934             for (int i = 0; i < skeleton.num_joints; i++) {
3935                 skeleton.joints[i].velocity = (animation[animCurrent].position[i][frameCurrent] * (1 - target) + animation[animTarget].position[i][frameTarget] * (target) - skeleton.joints[i].position) / multiplier;
3936                 skeleton.joints[i].position = animation[animCurrent].position[i][frameCurrent] * (1 - target) + animation[animTarget].position[i][frameTarget] * (target);
3937             }
3938             offset = currentoffset * (1 - target) + targetoffset * target;
3939             for (int i = 0; i < skeleton.num_muscles; i++) {
3940                 if (skeleton.muscles[i].visible) {
3941                     skeleton.muscles[i].rotate1 = skeleton.muscles[i].oldrotate1 * (1 - target) + skeleton.muscles[i].newrotate1 * (target);
3942                     skeleton.muscles[i].rotate2 = skeleton.muscles[i].oldrotate2 * (1 - target) + skeleton.muscles[i].newrotate2 * (target);
3943                     skeleton.muscles[i].rotate3 = skeleton.muscles[i].oldrotate3 * (1 - target) + skeleton.muscles[i].newrotate3 * (target);
3944                 }
3945             }
3946         }
3947
3948         if (isLanding() && landhard) {
3949             if (id == 0)
3950                 camerashake += .4;
3951             animTarget = getLandhard();
3952             frameTarget = 0;
3953             target = 0;
3954             landhard = 0;
3955             transspeed = 15;
3956         }
3957     }
3958 }
3959
3960 /* EFFECT
3961  * MONSTER
3962  * TODO
3963  */
3964 void Person::DoStuff()
3965 {
3966     static XYZ terrainnormal;
3967     static XYZ flatfacing;
3968     static XYZ flatvelocity;
3969     static float flatvelspeed;
3970     static int i, j, l;
3971     static XYZ average;
3972     static int howmany;
3973     static int bloodsize;
3974     static int startx, starty, endx, endy;
3975     static GLubyte color;
3976     static XYZ bloodvel;
3977
3978     onfiredelay -= multiplier;
3979     if (onfiredelay < 0 && onfire) {
3980         if (Random() % 2 == 0) {
3981             crouchkeydown = 1;
3982         }
3983         onfiredelay = 0.3;
3984     }
3985
3986     crouchkeydowntime += multiplier;
3987     if (!crouchkeydown)
3988         crouchkeydowntime = 0;
3989     jumpkeydowntime += multiplier;
3990     if (!jumpkeydown && skeleton.free)
3991         jumpkeydowntime = 0;
3992
3993     if (hostile || damage > 0 || bloodloss > 0)
3994         immobile = 0;
3995
3996     if (isIdle() || isRun())
3997         targetoffset = 0;
3998
3999     if (num_weapons == 1 && weaponactive != -1)
4000         weaponstuck = -1;
4001
4002     if (id == 0)
4003         blooddimamount -= multiplier * .3;
4004     speechdelay -= multiplier;
4005     texupdatedelay -= multiplier;
4006     interestdelay -= multiplier;
4007     flamedelay -= multiplier;
4008     parriedrecently -= multiplier;
4009     if (!victim) {
4010         victim = this->shared_from_this();
4011         hasvictim = 0;
4012     }
4013
4014     if (id == 0)
4015         speed = 1.1 * speedmult;
4016     else
4017         speed = 1.0 * speedmult;
4018     if (!skeleton.free)
4019         rabbitkickragdoll = 0;
4020
4021     speed *= speedmult;
4022
4023     if (id != 0 && (creature == rabbittype || difficulty != 2))
4024         superruntoggle = 0;
4025     if (id != 0 && creature == wolftype && difficulty == 2) {
4026         superruntoggle = 0;
4027         if (aitype != passivetype) {
4028             superruntoggle = 1;
4029             if (aitype == attacktypecutoff && (Person::players[0]->isIdle() || Person::players[0]->isCrouch() || Person::players[0]->skeleton.free || Person::players[0]->animTarget == getupfrombackanim || Person::players[0]->animTarget == getupfromfrontanim || Person::players[0]->animTarget == sneakanim) && distsq(&coords, &Person::players[0]->coords) < 16) {
4030                 superruntoggle = 0;
4031             }
4032         }
4033         if (scale < 0.2)
4034             superruntoggle = 0;
4035         if (animTarget == wolfrunninganim && !superruntoggle) {
4036             animTarget = getRun();
4037             frameTarget = 0;
4038         }
4039     }
4040     if (weaponactive == -1 && num_weapons > 0) {
4041         if (weapons[weaponids[0]].getType() == staff) {
4042             weaponactive = 0;
4043         }
4044     }
4045
4046     if (onfire) {
4047         burnt += multiplier;
4048         deathbleeding = 1;
4049         if (burnt > .6)
4050             burnt = .6;
4051         OPENAL_SetVolume(channels[stream_firesound], 256 + 256 * findLength(&velocity) / 3);
4052
4053         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
4054             float gLoc[3];
4055             float vel[3];
4056             gLoc[0] = coords.x;
4057             gLoc[1] = coords.y;
4058             gLoc[2] = coords.z;
4059             vel[0] = velocity.x;
4060             vel[1] = velocity.y;
4061             vel[2] = velocity.z;
4062
4063             if (id == 0) {
4064                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc, vel);
4065                 OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
4066             }
4067         }
4068     }
4069     while (flamedelay < 0 && onfire) {
4070         flamedelay += .006;
4071         howmany = abs(Random() % (skeleton.num_joints));
4072         if (skeleton.free) {
4073             flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
4074             flatfacing = skeleton.joints[howmany].position * scale + coords;
4075         } else {
4076             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
4077             flatvelocity = (coords - oldcoords) / multiplier / 2;
4078         }
4079         Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
4080     }
4081
4082     while (flamedelay < 0 && !onfire && tutoriallevel == 1 && id != 0) {
4083         flamedelay += .05;
4084         howmany = abs(Random() % (skeleton.num_joints));
4085         if (skeleton.free) {
4086             flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
4087             flatfacing = skeleton.joints[howmany].position * scale + coords;
4088         } else {
4089             flatvelocity = (coords - oldcoords) / multiplier / 2;
4090             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
4091         }
4092         Sprite::MakeSprite(breathsprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, .3);
4093     }
4094
4095     if (bleeding > 0) {
4096         bleeding -= multiplier * .3;
4097         if (bloodtoggle == 2) {
4098             skeleton.drawmodel.textureptr.bind();
4099             if ((bleeding <= 0) && (detail != 2))
4100                 DoMipmaps();
4101         }
4102     }
4103
4104     if (neckspurtamount > 0) {
4105         neckspurtamount -= multiplier;
4106         neckspurtdelay -= multiplier * 3;
4107         neckspurtparticledelay -= multiplier * 3;
4108         if (neckspurtparticledelay < 0 && neckspurtdelay > 2) {
4109             spurt = 0;
4110             bloodvel = 0;
4111             if (skeleton.free) {
4112                 bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0);
4113                 bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
4114                 Sprite::MakeSprite(bloodsprite, (jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5)*scale + coords, bloodvel, 1, 1, 1, .05, .9);
4115             } else {
4116                 bloodvel.z = 5 * neckspurtamount;
4117                 bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
4118                 bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0) * scale;
4119                 Sprite::MakeSprite(bloodsprite, DoRotation(jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, .9);
4120             }
4121             neckspurtparticledelay = .05;
4122         }
4123         if (neckspurtdelay < 0) {
4124             neckspurtdelay = 3;
4125         }
4126     }
4127
4128     if (deathbleeding > 0 && dead != 2) {
4129         if (deathbleeding < 5)
4130             bleeddelay -= deathbleeding * multiplier / 4;
4131         else
4132             bleeddelay -= 5 * multiplier / 4;
4133         if (bleeddelay < 0 && bloodtoggle) {
4134             bleeddelay = 1;
4135             XYZ bloodvel;
4136             if (bloodtoggle) {
4137                 bloodvel = 0;
4138                 if (skeleton.free) {
4139                     bloodvel += DoRotation(jointVel(abdomen), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
4140                     Sprite::MakeSprite(bloodsprite, jointPos(abdomen) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
4141                 } else {
4142                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
4143                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(abdomen) + jointPos(abdomen)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
4144                 }
4145             }
4146         }
4147         bloodloss += deathbleeding * multiplier * 80;
4148         deathbleeding -= multiplier * 1.6;
4149         if (deathbleeding < 0)
4150             deathbleeding = 0;
4151         if (bloodloss > damagetolerance && animation[animTarget].attack == neutral) {
4152             if (weaponactive != -1) {
4153                 weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
4154                 weapons[weaponids[0]].velocity.x += .01;
4155                 num_weapons--;
4156                 if (num_weapons) {
4157                     weaponids[0] = weaponids[num_weapons];
4158                     if (weaponstuck == num_weapons)
4159                         weaponstuck = 0;
4160                 }
4161                 weaponactive = -1;
4162                 for (unsigned i = 0; i < Person::players.size(); i++) {
4163                     Person::players[i]->wentforweapon = 0;
4164                 }
4165
4166                 if (id == 0) {
4167                     flashamount = .5;
4168                     flashr = 1;
4169                     flashg = 0;
4170                     flashb = 0;
4171                     flashdelay = 0;
4172                 }
4173             }
4174
4175             if (!dead && creature == wolftype) {
4176                 award_bonus(0, Wolfbonus);
4177             }
4178             dead = 2;
4179             if (animTarget == knifefollowedanim && !skeleton.free) {
4180                 for (int i = 0; i < skeleton.num_joints; i++) {
4181                     skeleton.joints[i].velocity = 0;
4182                     skeleton.joints[i].velocity.y = -2;
4183                 }
4184             }
4185             if (id != 0 && unconscioustime > .1) {
4186                 numafterkill++;
4187             }
4188
4189             RagDoll(0);
4190         }
4191     }
4192
4193     if (texupdatedelay < 0 && bleeding > 0 && bloodtoggle == 2 && distsq(&viewer, &coords) < 9) {
4194         texupdatedelay = .12;
4195
4196         bloodsize = 5 - realtexdetail;
4197
4198         startx = 0;
4199         starty = 0;
4200         startx = bleedy; //abs(Random()%(skeleton.skinsize-bloodsize-1));
4201         starty = bleedx; //abs(Random()%(skeleton.skinsize-bloodsize-1));
4202         endx = startx + bloodsize;
4203         endy = starty + bloodsize;
4204
4205         if (startx < 0) {
4206             startx = 0;
4207             bleeding = 0;
4208         }
4209         if (starty < 0) {
4210             starty = 0;
4211             bleeding = 0;
4212         }
4213         if (endx > skeleton.skinsize - 1) {
4214             endx = skeleton.skinsize - 1;
4215             bleeding = 0;
4216         }
4217         if (endy > skeleton.skinsize - 1) {
4218             endy = skeleton.skinsize - 1;
4219             bleeding = 0;
4220         }
4221         if (endx < startx)
4222             endx = startx;
4223         if (endy < starty)
4224             endy = starty;
4225
4226         for (i = startx; i < endx; i++) {
4227             for (j = starty; j < endy; j++) {
4228                 if (Random() % 2 == 0) {
4229                     color = Random() % 85 + 170;
4230                     if (skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] > color / 2)
4231                         skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] = color / 2;
4232                     skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 1] = 0;
4233                     skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 2] = 0;
4234                 }
4235             }
4236         }
4237         if (detail > 1) {
4238             skeleton.drawmodel.textureptr.bind();
4239             DoMipmaps();
4240         }
4241
4242         if (skeleton.free) {
4243             bleedx += 4 * direction / realtexdetail;
4244             if (detail == 2)
4245                 bleedy += (abs(Random() % 3) - 1) * 2 / realtexdetail;
4246             else
4247                 bleedy += (abs(Random() % 3) - 1) * 4 / realtexdetail;
4248         } else {
4249             bleedy -= 4 / realtexdetail;
4250             if (detail == 2)
4251                 bleedx += (abs(Random() % 3) - 1) * 2 / realtexdetail;
4252             else
4253                 bleedx += (abs(Random() % 3) - 1) * 4 / realtexdetail;
4254         }
4255     }
4256
4257     if (abs(righthandmorphness - targetrighthandmorphness) < multiplier * 4) {
4258         righthandmorphness = targetrighthandmorphness;
4259         righthandmorphstart = righthandmorphend;
4260     } else if (righthandmorphness > targetrighthandmorphness) {
4261         righthandmorphness -= multiplier * 4;
4262     } else if (righthandmorphness < targetrighthandmorphness) {
4263         righthandmorphness += multiplier * 4;
4264     }
4265
4266     if (abs(lefthandmorphness - targetlefthandmorphness) < multiplier * 4) {
4267         lefthandmorphness = targetlefthandmorphness;
4268         lefthandmorphstart = lefthandmorphend;
4269     } else if (lefthandmorphness > targetlefthandmorphness) {
4270         lefthandmorphness -= multiplier * 4;
4271     } else if (lefthandmorphness < targetlefthandmorphness) {
4272         lefthandmorphness += multiplier * 4;
4273     }
4274
4275     if (creature == rabbittype || targettailmorphness == 5 || targettailmorphness == 0) {
4276         if (abs(tailmorphness - targettailmorphness) < multiplier * 10) {
4277             tailmorphness = targettailmorphness;
4278             tailmorphstart = tailmorphend;
4279         } else if (tailmorphness > targettailmorphness) {
4280             tailmorphness -= multiplier * 10;
4281         } else if (tailmorphness < targettailmorphness) {
4282             tailmorphness += multiplier * 10;
4283         }
4284     }
4285
4286     if (creature == wolftype) {
4287         if (abs(tailmorphness - targettailmorphness) < multiplier * 4) {
4288             tailmorphness = targettailmorphness;
4289             tailmorphstart = tailmorphend;
4290         } else if (tailmorphness > targettailmorphness) {
4291             tailmorphness -= multiplier * 2;
4292         } else if (tailmorphness < targettailmorphness) {
4293             tailmorphness += multiplier * 2;
4294         }
4295     }
4296
4297     if (headmorphend == 3 || headmorphstart == 3) {
4298         if (abs(headmorphness - targetheadmorphness) < multiplier * 7) {
4299             headmorphness = targetheadmorphness;
4300             headmorphstart = headmorphend;
4301         } else if (headmorphness > targetheadmorphness) {
4302             headmorphness -= multiplier * 7;
4303         } else if (headmorphness < targetheadmorphness) {
4304             headmorphness += multiplier * 7;
4305         }
4306     } else if (headmorphend == 5 || headmorphstart == 5) {
4307         if (abs(headmorphness - targetheadmorphness) < multiplier * 10) {
4308             headmorphness = targetheadmorphness;
4309             headmorphstart = headmorphend;
4310         } else if (headmorphness > targetheadmorphness) {
4311             headmorphness -= multiplier * 10;
4312         } else if (headmorphness < targetheadmorphness) {
4313             headmorphness += multiplier * 10;
4314         }
4315     } else {
4316         if (abs(headmorphness - targetheadmorphness) < multiplier * 4) {
4317             headmorphness = targetheadmorphness;
4318             headmorphstart = headmorphend;
4319         } else if (headmorphness > targetheadmorphness) {
4320             headmorphness -= multiplier * 4;
4321         } else if (headmorphness < targetheadmorphness) {
4322             headmorphness += multiplier * 4;
4323         }
4324     }
4325
4326     if (abs(chestmorphness - targetchestmorphness) < multiplier) {
4327         chestmorphness = targetchestmorphness;
4328         chestmorphstart = chestmorphend;
4329     } else if (chestmorphness > targetchestmorphness) {
4330         chestmorphness -= multiplier;
4331     } else if (chestmorphness < targetchestmorphness) {
4332         chestmorphness += multiplier;
4333     }
4334
4335     if (dead != 2 && howactive <= typesleeping) {
4336         if (chestmorphstart == 0 && chestmorphend == 0) {
4337             chestmorphness = 0;
4338             targetchestmorphness = 1;
4339             chestmorphend = 3;
4340         }
4341         if (chestmorphstart != 0 && chestmorphend != 0) {
4342             chestmorphness = 0;
4343             targetchestmorphness = 1;
4344             chestmorphend = 0;
4345             if (environment == snowyenvironment) {
4346                 XYZ footpoint;
4347                 XYZ footvel;
4348                 if (skeleton.free) {
4349                     footvel = skeleton.specialforward[0] * -1;
4350                     footpoint = ((jointPos(head) + jointPos(neck)) / 2) * scale + coords;
4351                 } else {
4352                     footvel = DoRotation(skeleton.specialforward[0], 0, yaw, 0) * -1;
4353                     footpoint = DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords;
4354                 }
4355                 if (animTarget == sleepanim)
4356                     footvel = DoRotation(footvel, 0, 90, 0);
4357                 Sprite::MakeSprite(breathsprite, footpoint + footvel * .2, footvel * .4, 1, 1, 1, .4, .3);
4358             }
4359         }
4360
4361         if (!dead && howactive < typesleeping) {
4362             blinkdelay -= multiplier * 2;
4363             if (headmorphstart == 0 && headmorphend == 0 && blinkdelay <= 0) {
4364                 headmorphness = 0;
4365                 targetheadmorphness = 1;
4366                 headmorphend = 3;
4367                 blinkdelay = (float)(abs(Random() % 40)) / 5;
4368             }
4369             if (headmorphstart == 3 && headmorphend == 3) {
4370                 headmorphness = 0;
4371                 targetheadmorphness = 1;
4372                 headmorphend = 0;
4373             }
4374         }
4375         if (!dead) {
4376             twitchdelay -= multiplier * 1.5;
4377             if (animTarget != hurtidleanim) {
4378                 if (headmorphstart == 0 && headmorphend == 0 && twitchdelay <= 0) {
4379                     headmorphness = 0;
4380                     targetheadmorphness = 1;
4381                     headmorphend = 5;
4382                     twitchdelay = (float)(abs(Random() % 40)) / 5;
4383                 }
4384                 if (headmorphstart == 5 && headmorphend == 5) {
4385                     headmorphness = 0;
4386                     targetheadmorphness = 1;
4387                     headmorphend = 0;
4388                 }
4389             }
4390             if ((isIdle() || isCrouch()) && animTarget != hurtidleanim) {
4391                 twitchdelay3 -= multiplier * 1;
4392                 if (Random() % 2 == 0) {
4393                     if (righthandmorphstart == 0 && righthandmorphend == 0 && twitchdelay3 <= 0) {
4394                         righthandmorphness = 0;
4395                         targetrighthandmorphness = 1;
4396                         righthandmorphend = 1;
4397                         if (Random() % 2 == 0)twitchdelay3 = (float)(abs(Random() % 40)) / 5;
4398                     }
4399                     if (righthandmorphstart == 1 && righthandmorphend == 1) {
4400                         righthandmorphness = 0;
4401                         targetrighthandmorphness = 1;
4402                         righthandmorphend = 0;
4403                     }
4404                 }
4405                 if (Random() % 2 == 0) {
4406                     if (lefthandmorphstart == 0 && lefthandmorphend == 0 && twitchdelay3 <= 0) {
4407                         lefthandmorphness = 0;
4408                         targetlefthandmorphness = 1;
4409                         lefthandmorphend = 1;
4410                         twitchdelay3 = (float)(abs(Random() % 40)) / 5;
4411                     }
4412                     if (lefthandmorphstart == 1 && lefthandmorphend == 1) {
4413                         lefthandmorphness = 0;
4414                         targetlefthandmorphness = 1;
4415                         lefthandmorphend = 0;
4416                     }
4417                 }
4418             }
4419         }
4420         if (!dead) {
4421             if (creature == rabbittype) {
4422                 if (howactive < typesleeping)
4423                     twitchdelay2 -= multiplier * 1.5;
4424                 else
4425                     twitchdelay2 -= multiplier * 0.5;
4426                 if (howactive <= typesleeping) {
4427                     if (tailmorphstart == 0 && tailmorphend == 0 && twitchdelay2 <= 0) {
4428                         tailmorphness = 0;
4429                         targettailmorphness = 1;
4430                         tailmorphend = 1;
4431                         twitchdelay2 = (float)(abs(Random() % 40)) / 5;
4432                     }
4433                     if (tailmorphstart == 1 && tailmorphend == 1) {
4434                         tailmorphness = 0;
4435                         targettailmorphness = 1;
4436                         tailmorphend = 2;
4437                     }
4438                     if (tailmorphstart == 2 && tailmorphend == 2) {
4439                         tailmorphness = 0;
4440                         targettailmorphness = 1;
4441                         tailmorphend = 0;
4442                     }
4443                 }
4444             }
4445         }
4446     }
4447     if (creature == wolftype) {
4448         twitchdelay2 -= multiplier * 1.5;
4449         if (tailmorphend != 0)
4450             if ((isRun() || animTarget == jumpupanim || animTarget == jumpdownanim || animTarget == backflipanim) && !skeleton.free) {
4451                 tailmorphness = 0;
4452                 targettailmorphness = 1;
4453                 tailmorphend = 0;
4454                 twitchdelay2 = .1;
4455             }
4456         if (tailmorphend != 5)
4457             if (animTarget == flipanim || animTarget == frontflipanim || animTarget == rollanim || skeleton.free) {
4458                 tailmorphness = 0;
4459                 targettailmorphness = 1;
4460                 tailmorphend = 5;
4461                 twitchdelay2 = .1;
4462             }
4463         if (twitchdelay2 <= 0) {
4464             if (((tailmorphstart == 0 && tailmorphend == 0) || (tailmorphstart == 5 && tailmorphend == 5))) {
4465                 tailmorphness = 0;
4466                 targettailmorphness = 1;
4467                 tailmorphend = 1;
4468             }
4469             if (tailmorphstart == 1 && tailmorphend == 1) {
4470                 tailmorphness = 0;
4471                 targettailmorphness = 1;
4472                 tailmorphend = 2;
4473             }
4474             if (tailmorphstart == 2 && tailmorphend == 2) {
4475                 tailmorphness = 0;
4476                 targettailmorphness = 1;
4477                 tailmorphend = 3;
4478             }
4479             if (tailmorphstart == 3 && tailmorphend == 3) {
4480                 tailmorphness = 0;
4481                 targettailmorphness = 1;
4482                 tailmorphend = 4;
4483             }
4484             if (tailmorphstart == 4 && tailmorphend == 4) {
4485                 tailmorphness = 0;
4486                 targettailmorphness = 1;
4487                 tailmorphend = 1;
4488             }
4489         }
4490     }
4491
4492     if (dead != 1)
4493         unconscioustime = 0;
4494
4495     if (dead == 1 || howactive == typesleeping) {
4496         unconscioustime += multiplier;
4497         //If unconscious, close eyes and mouth
4498         if (righthandmorphend != 0)
4499             righthandmorphness = 0;
4500         righthandmorphend = 0;
4501         targetrighthandmorphness = 1;
4502
4503         if (lefthandmorphend != 0)
4504             lefthandmorphness = 0;
4505         lefthandmorphend = 0;
4506         targetlefthandmorphness = 1;
4507
4508         if (headmorphend != 3 && headmorphend != 5)
4509             headmorphness = 0;
4510         headmorphend = 3;
4511         targetheadmorphness = 1;
4512     }
4513
4514
4515     if (howactive > typesleeping) {
4516         XYZ headpoint;
4517         headpoint = coords;
4518         if (bloodtoggle && !bled) {
4519             terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
4520         }
4521         if (bloodtoggle && !bled)
4522             for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
4523                 j = terrain.patchobjects[whichpatchx][whichpatchz][l];
4524                 XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
4525                 float size = .8;
4526                 float opacity = .6;
4527                 float yaw = 0;
4528                 objects.model[j].MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
4529             }
4530         bled = 1;
4531     }
4532
4533     if (dead == 2 || howactive > typesleeping) {
4534         //If dead, open mouth and hands
4535         if (righthandmorphend != 0)
4536             righthandmorphness = 0;
4537         righthandmorphend = 0;
4538         targetrighthandmorphness = 1;
4539
4540         if (lefthandmorphend != 0)
4541             lefthandmorphness = 0;
4542         lefthandmorphend = 0;
4543         targetlefthandmorphness = 1;
4544
4545         if (headmorphend != 2)
4546             headmorphness = 0;
4547         headmorphend = 2;
4548         targetheadmorphness = 1;
4549     }
4550
4551     if (stunned > 0 && !dead && headmorphend != 2) {
4552         if (headmorphend != 4)
4553             headmorphness = 0;
4554         headmorphend = 4;
4555         targetheadmorphness = 1;
4556     }
4557
4558     if (damage > damagetolerance && !dead) {
4559
4560         dead = 1;
4561         unconscioustime = 0;
4562
4563         if (creature == wolftype) {
4564             award_bonus(0, Wolfbonus);
4565         }
4566
4567         RagDoll(0);
4568
4569         if (weaponactive != -1) {
4570             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
4571             weapons[weaponids[0]].velocity.x += .01;
4572             num_weapons--;
4573             if (num_weapons) {
4574                 weaponids[0] = weaponids[num_weapons];
4575                 if (weaponstuck == num_weapons)
4576                     weaponstuck = 0;
4577             }
4578             weaponactive = -1;
4579             for (unsigned i = 0; i < Person::players.size(); i++) {
4580                 Person::players[i]->wentforweapon = 0;
4581             }
4582         }
4583
4584
4585
4586         if ((id == 0 || distsq(&coords, &viewer) < 50) && autoslomo) {
4587             slomo = 1;
4588             slomodelay = .2;
4589         }
4590
4591         damage += 20;
4592     }
4593
4594     if (!dead)
4595         damage -= multiplier * 13;
4596     if (!dead)
4597         permanentdamage -= multiplier * 4;
4598     if (isIdle() || isCrouch()) {
4599         if (!dead)
4600             permanentdamage -= multiplier * 4;
4601     }
4602     if (damage < 0)
4603         damage = 0;
4604     if (permanentdamage < 0)
4605         permanentdamage = 0;
4606     if (superpermanentdamage < 0)
4607         superpermanentdamage = 0;
4608     if (permanentdamage < superpermanentdamage) {
4609         permanentdamage = superpermanentdamage;
4610     }
4611     if (damage < permanentdamage) {
4612         damage = permanentdamage;
4613     }
4614     if (dead == 1 && damage < damagetolerance) {
4615         dead = 0;
4616         skeleton.free = 1;
4617         damage -= 20;
4618         for (int i = 0; i < skeleton.num_joints; i++) {
4619             skeleton.joints[i].velocity = 0;
4620         }
4621     }
4622     if (permanentdamage > damagetolerance && dead != 2) {
4623         DoBlood(1, 255);
4624
4625         if (weaponactive != -1) {
4626             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
4627             weapons[weaponids[0]].velocity.x += .01;
4628             num_weapons--;
4629             if (num_weapons) {
4630                 weaponids[0] = weaponids[num_weapons];
4631                 if (weaponstuck == num_weapons)
4632                     weaponstuck = 0;
4633             }
4634             weaponactive = -1;
4635             for (unsigned i = 0; i < Person::players.size(); i++) {
4636                 Person::players[i]->wentforweapon = 0;
4637             }
4638         }
4639
4640         bled = 0;
4641
4642         if (!dead && creature == wolftype) {
4643             award_bonus(0, Wolfbonus);
4644         }
4645
4646         if (unconscioustime < .1 && (bonus != spinecrusher || bonustime > 1) && (bonus != FinishedBonus || bonustime > 1) && bloodloss < damagetolerance)
4647             award_bonus(id, touchofdeath);
4648         if (id != 0 && unconscioustime > .1) {
4649             numafterkill++;
4650         }
4651
4652         dead = 2;
4653
4654         skeleton.free = 1;
4655
4656         emit_sound_at(breaksound, coords);
4657     }
4658
4659     if (skeleton.free == 1) {
4660         if (id == 0)
4661             pause_sound(whooshsound);
4662
4663         if (!dead) {
4664             //If knocked over, open hands and close mouth
4665             if (righthandmorphend != 0)
4666                 righthandmorphness = 0;
4667             righthandmorphend = 0;
4668             targetrighthandmorphness = 1;
4669
4670             if (lefthandmorphend != 0)
4671                 lefthandmorphness = 0;
4672             lefthandmorphend = 0;
4673             targetlefthandmorphness = 1;
4674
4675             if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5) {
4676                 if (headmorphend != 0)
4677                     headmorphness = 0;
4678                 headmorphend = 0;
4679                 targetheadmorphness = 1;
4680             }
4681         }
4682
4683         skeleton.DoGravity(&scale);
4684         float damageamount;
4685         damageamount = skeleton.DoConstraints(&coords, &scale) * 5;
4686         if (damage > damagetolerance - damageamount && !dead && (bonus != spinecrusher || bonustime > 1) && (bonus != style || bonustime > 1) && (bonus != cannon || bonustime > 1))
4687             award_bonus(id, deepimpact);
4688         DoDamage(damageamount / ((protectionhigh + protectionhead + protectionlow) / 3));
4689
4690         average = 0;
4691         howmany = 0;
4692         for (j = 0; j < skeleton.num_joints; j++) {
4693             average += skeleton.joints[j].position;
4694             howmany++;
4695         }
4696         average /= howmany;
4697         coords += average * scale;
4698         for (j = 0; j < skeleton.num_joints; j++) {
4699             skeleton.joints[j].position -= average;
4700         }
4701         average /= multiplier;
4702
4703         velocity = 0;
4704         for (int i = 0; i < skeleton.num_joints; i++) {
4705             velocity += skeleton.joints[i].velocity * scale;
4706         }
4707         velocity /= skeleton.num_joints;
4708
4709         if (!isnormal(velocity.x) && velocity.x) {
4710             velocity = 0;
4711         }
4712
4713         if (findLength(&average) < 10 && dead && skeleton.free) {
4714             skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
4715             if (skeleton.longdead > 2000) {
4716                 if (skeleton.longdead > 6000) {
4717                     if (id == 0)
4718                         pause_sound(whooshsound);
4719                     skeleton.free = 3;
4720                     DrawSkeleton();
4721                     skeleton.free = 2;
4722                 }
4723                 if (dead == 2 && bloodloss < damagetolerance) {
4724                     XYZ headpoint;
4725                     headpoint = (jointPos(head) + jointPos(neck)) / 2 * scale + coords;
4726                     DoBlood(1, 255);
4727                     if (bloodtoggle && !bled) {
4728                         terrain.MakeDecal(blooddecal, headpoint, .2 * 1.2, .5, 0);
4729                     }
4730                     if (bloodtoggle && !bled)
4731                         for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
4732                             j = terrain.patchobjects[whichpatchx][whichpatchz][l];
4733                             XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
4734                             float size = .2 * 1.2;
4735                             float opacity = .6;
4736                             float yaw = 0;
4737                             objects.model[j].MakeDecal(blooddecal, &point, &size, &opacity, &yaw);
4738                         }
4739                     bled = 1;
4740                 }
4741                 if (dead == 2 && bloodloss >= damagetolerance) {
4742                     XYZ headpoint;
4743                     headpoint = (jointPos(abdomen) + jointPos(neck)) / 2 * scale + coords;
4744                     if (bleeding <= 0)
4745                         DoBlood(1, 255);
4746                     if (bloodtoggle && !bled) {
4747                         terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
4748                     }
4749                     if (bloodtoggle && !bled)
4750                         for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
4751                             j = terrain.patchobjects[whichpatchx][whichpatchz][l];
4752                             XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
4753                             float size = .8;
4754                             float opacity = .6;
4755                             float yaw = 0;
4756                             objects.model[j].MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
4757                         }
4758                     bled = 1;
4759                 }
4760             }
4761         }
4762
4763         if (!dead && crouchkeydown && skeleton.freetime > .5 && id == 0 && skeleton.free) {
4764             bool canrecover = 1;
4765             XYZ startpoint, endpoint, colpoint, colviewer, coltarget;
4766             startpoint = coords;
4767             endpoint = coords;
4768             endpoint.y -= .7;
4769             if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1)
4770                 canrecover = 0;
4771             if (velocity.y < -30)
4772                 canrecover = 0;
4773             for (i = 0; i < objects.numobjects; i++) {
4774                 if (objects.type[i] != treeleavestype && objects.type[i] != bushtype && objects.type[i] != firetype) {
4775                     colviewer = startpoint;
4776                     coltarget = endpoint;
4777                     if (objects.model[i].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
4778                         canrecover = 0;
4779                 }
4780             }
4781             if (canrecover) {
4782                 skeleton.free = 0;
4783                 XYZ middle;
4784                 middle = 0;
4785
4786                 terrainnormal = jointPos(groin) - jointPos(abdomen);
4787                 if (joint(groin).locked && joint(abdomen).locked) {
4788                     terrainnormal = jointPos(groin) - jointPos(abdomen);
4789                     middle = (jointPos(groin) + jointPos(abdomen)) / 2;
4790                 }
4791                 if (joint(abdomen).locked && joint(neck).locked) {
4792                     terrainnormal = jointPos(abdomen) - jointPos(neck);
4793                     middle = (jointPos(neck) + jointPos(abdomen)) / 2;
4794                 }
4795                 if (joint(groin).locked && joint(neck).locked) {
4796                     terrainnormal = jointPos(groin) - jointPos(neck);
4797                     middle = (jointPos(groin) + jointPos(neck)) / 2;
4798                 }
4799                 Normalise(&terrainnormal);
4800
4801                 targetyaw = -asin(0 - terrainnormal.x);
4802                 targetyaw *= 360 / 6.28;
4803                 if (terrainnormal.z < 0)
4804                     targetyaw = 180 - targetyaw;
4805                 yaw = targetyaw;
4806
4807                 frameTarget = 0;
4808                 animTarget = flipanim;
4809                 crouchtogglekeydown = 1;
4810                 target = 0;
4811                 tilt2 = 0;
4812                 targettilt2 = 0;
4813
4814                 animCurrent = tempanim;
4815                 frameCurrent = 0;
4816                 target = 0;
4817
4818                 for (int i = 0; i < skeleton.num_joints; i++) {
4819                     tempanimation.position[i][0] = skeleton.joints[i].position;
4820                     tempanimation.position[i][0] = DoRotation(tempanimation.position[i][0], 0, -yaw, 0);
4821                 }
4822             }
4823         }
4824
4825         if (findLength(&average) < 10 && !dead && skeleton.free) {
4826             skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
4827             if (skeleton.longdead > (damage + 500) * 1.5) {
4828                 if (id == 0)
4829                     pause_sound(whooshsound);
4830                 skeleton.free = 0;
4831                 velocity = 0;
4832                 XYZ middle;
4833                 middle = 0;
4834
4835                 terrainnormal = jointPos(groin) - jointPos(abdomen);
4836                 if (joint(groin).locked && joint(abdomen).locked) {
4837                     terrainnormal = jointPos(groin) - jointPos(abdomen);
4838                     middle = (jointPos(groin) + jointPos(abdomen)) / 2;
4839                 }
4840                 if (joint(abdomen).locked && joint(neck).locked) {
4841                     terrainnormal = jointPos(abdomen) - jointPos(neck);
4842                     middle = (jointPos(neck) + jointPos(abdomen)) / 2;
4843                 }
4844                 if (joint(groin).locked && joint(neck).locked) {
4845                     terrainnormal = jointPos(groin) - jointPos(neck);
4846                     middle = (jointPos(groin) + jointPos(neck)) / 2;
4847                 }
4848                 Normalise(&terrainnormal);
4849
4850                 targetyaw = -asin(0 - terrainnormal.x);
4851                 targetyaw *= 360 / 6.28;
4852                 if (terrainnormal.z < 0)
4853                     targetyaw = 180 - targetyaw;
4854                 yaw = targetyaw;
4855
4856                 targettilt2 = asin(terrainnormal.y) * 180 / 3.14 * -1;
4857
4858
4859                 if (skeleton.forward.y < 0) {
4860                     animTarget = getupfrombackanim;
4861                     frameTarget = 0;
4862                     targettilt2 = 0;
4863                 }
4864                 if (skeleton.forward.y > -.3) {
4865                     animTarget = getupfromfrontanim;
4866                     yaw += 180;
4867                     targetyaw += 180;
4868                     targettilt2 *= -1;
4869                     frameTarget = 0;
4870                     targettilt2 = 0;
4871                 }
4872
4873                 if ((Random() % 8 == 0 && id != 0 && creature == rabbittype) || (Random() % 2 == 0 && id != 0 && creature == wolftype) || (id == 0 && crouchkeydown && (forwardkeydown || backkeydown || leftkeydown || rightkeydown))) {
4874                     animTarget = rollanim;
4875                     targetyaw = lookyaw;
4876                     if (id == 0) {
4877                         if (rightkeydown) {
4878                             targetyaw -= 90;
4879                             if (forwardkeydown)
4880                                 targetyaw += 45;
4881                             if (backkeydown)
4882                                 targetyaw -= 45;
4883                         }
4884                         if (leftkeydown) {
4885                             targetyaw += 90;
4886                             if (forwardkeydown)
4887                                 targetyaw -= 45;
4888                             if (backkeydown)
4889                                 targetyaw += 45;
4890                         }
4891                         if (backkeydown) {
4892                             if ( !leftkeydown && !rightkeydown)
4893                                 targetyaw += 180;
4894                         }
4895                         targetyaw += 180;
4896                     }
4897                 }
4898
4899                 if (abs(targettilt2) > 50)
4900                     targettilt2 = 0;
4901                 animCurrent = tempanim;
4902                 frameCurrent = 0;
4903                 target = 0;
4904                 tilt2 = targettilt2;
4905
4906                 if (middle.y > 0 && animTarget != rollanim)
4907                     targetoffset.y = middle.y + 1;
4908
4909                 for (int i = 0; i < skeleton.num_joints; i++) {
4910                     tempanimation.position[i][0] = skeleton.joints[i].position;
4911                     tempanimation.position[i][0] = DoRotation(tempanimation.position[i][0], 0, -yaw, 0);
4912                 }
4913             }
4914         }
4915
4916         bool hasstaff;
4917         hasstaff = 0;
4918         if (num_weapons > 0)
4919             if (weapons[0].getType() == staff)
4920                 hasstaff = 1;
4921         if (!skeleton.freefall && freefall && ((jumpkeydown && jumpkeydowntime < .2) || (hasstaff && rabbitkickragdoll)) && !dead) {
4922             if (velocity.y > -30) {
4923                 XYZ tempvelocity;
4924                 tempvelocity = velocity;
4925                 Normalise(&tempvelocity);
4926                 targetyaw = -asin(0 - tempvelocity.x);
4927                 targetyaw *= 360 / 6.28;
4928                 if (velocity.z < 0)
4929                     targetyaw = 180 - targetyaw;
4930                 //targetyaw+=180;
4931
4932                 skeleton.free = 0;
4933                 if (dotproduct(&skeleton.forward, &tempvelocity) < 0) {
4934                     animTarget = rollanim;
4935                     frameTarget = 2;
4936                 } else {
4937                     animTarget = backhandspringanim;
4938                     targetyaw += 180;
4939                     frameTarget = 6;
4940                 }
4941                 target = 0;
4942
4943                 emit_sound_at(movewhooshsound, coords, 128.);
4944
4945                 animCurrent = animTarget;
4946                 frameCurrent = frameTarget - 1;
4947                 target = 0;
4948
4949                 velocity = 0;
4950
4951                 yaw = targetyaw;
4952                 tilt = 0;
4953                 targettilt = 0;
4954                 tilt2 = 0;
4955                 targettilt2 = 0;
4956             }
4957         }
4958         if (skeleton.freefall == 0)
4959             freefall = 0;
4960
4961     }
4962
4963     if (aitype != passivetype || skeleton.free == 1)
4964         if (findLengthfast(&velocity) > .1)
4965             for (i = 0; i < objects.numobjects; i++) {
4966                 if (objects.type[i] == firetype)
4967                     if (distsqflat(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 12 && distsq(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 49) {
4968                         if (onfire) {
4969                             if (!objects.onfire[i]) {
4970                                 emit_sound_at(firestartsound, objects.position[i]);
4971                             }
4972                             objects.onfire[i] = 1;
4973                         }
4974                         if (!onfire) {
4975                             if (objects.onfire[i]) {
4976                                 CatchFire();
4977                             }
4978                         }
4979                     }
4980                 if (objects.type[i] == bushtype)
4981                     if (distsqflat(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 12 && distsq(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 49) {
4982                         if (onfire) {
4983                             if (!objects.onfire[i]) {
4984                                 emit_sound_at(firestartsound, objects.position[i]);
4985                             }
4986                             objects.onfire[i] = 1;
4987                         }
4988
4989                         if (!onfire) {
4990                             if (objects.onfire[i]) {
4991                                 CatchFire();
4992                             }
4993                         }
4994                         if (objects.messedwith[i] <= 0) {
4995                             XYZ tempvel;
4996                             XYZ pos;
4997
4998                             emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
4999
5000                             if (id == 0) {
5001                                 envsound[numenvsounds] = coords;
5002                                 envsoundvol[numenvsounds] = 4 * findLength(&velocity);
5003                                 envsoundlife[numenvsounds] = .4;
5004                                 numenvsounds++;
5005                             }
5006
5007                             int howmany;
5008                             if (environment == grassyenvironment)
5009                                 howmany = findLength(&velocity) * 4;
5010                             if (environment == snowyenvironment)
5011                                 howmany = findLength(&velocity) * 2;
5012                             if (detail == 2)
5013                                 if (environment != desertenvironment)
5014                                     for (j = 0; j < howmany; j++) {
5015                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5016                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5017                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5018                                         pos = coords;
5019                                         pos.y += 1;
5020                                         pos.x += float(abs(Random() % 100) - 50) / 200;
5021                                         pos.y += float(abs(Random() % 100) - 50) / 200;
5022                                         pos.z += float(abs(Random() % 100) - 50) / 200;
5023                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
5024                                         Sprite::setLastSpriteSpecial(1);
5025                                     }
5026                             howmany = findLength(&velocity) * 4;
5027                             if (detail == 2)
5028                                 if (environment == snowyenvironment)
5029                                     for (j = 0; j < howmany; j++) {
5030                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5031                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5032                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5033                                         pos = coords;
5034                                         pos.y += 1;
5035                                         pos.x += float(abs(Random() % 100) - 50) / 200;
5036                                         pos.y += float(abs(Random() % 100) - 50) / 200;
5037                                         pos.z += float(abs(Random() % 100) - 50) / 200;
5038                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
5039                                         Sprite::setLastSpriteSpecial(2);
5040                                     }
5041                         }
5042                         objects.rotx[i] += velocity.x * multiplier * 6;
5043                         objects.roty[i] += velocity.z * multiplier * 6;
5044                         objects.messedwith[i] = .5;
5045                     }
5046                 XYZ tempcoord;
5047                 if (objects.type[i] == treeleavestype && environment != desertenvironment) {
5048                     if (objects.pitch[i] == 0)
5049                         tempcoord = coords;
5050                     else {
5051                         tempcoord = coords - objects.position[i];
5052                         tempcoord = DoRotation(tempcoord, 0, -objects.yaw[i], 0);
5053                         tempcoord = DoRotation(tempcoord, -objects.pitch[i], 0, 0);
5054                         tempcoord += objects.position[i];
5055                     }
5056                     if (distsqflat(&tempcoord, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 8 && distsq(&tempcoord, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 300 && tempcoord.y > objects.position[i].y + 3 * objects.scale[i]) {
5057                         if (objects.messedwith[i] <= 0) {
5058                             XYZ tempvel;
5059                             XYZ pos;
5060
5061                             emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
5062
5063                             if (id == 0) {
5064                                 envsound[numenvsounds] = coords;
5065                                 envsoundvol[numenvsounds] = 4 * findLength(&velocity);
5066                                 envsoundlife[numenvsounds] = .4;
5067                                 numenvsounds++;
5068                             }
5069
5070                             int howmany;
5071                             if (environment == grassyenvironment)
5072                                 howmany = findLength(&velocity) * 4;
5073                             if (environment == snowyenvironment)
5074                                 howmany = findLength(&velocity) * 2;
5075                             if (detail == 2)
5076                                 if (environment != desertenvironment)
5077                                     for (j = 0; j < howmany; j++) {
5078                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5079                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5080                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5081                                         pos = coords;
5082                                         pos += velocity * .1;
5083                                         pos.y += 1;
5084                                         pos.x += float(abs(Random() % 100) - 50) / 150;
5085                                         pos.y += float(abs(Random() % 100) - 50) / 150;
5086                                         pos.z += float(abs(Random() % 100) - 50) / 150;
5087                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
5088                                         Sprite::setLastSpriteSpecial(1);
5089                                     }
5090                             howmany = findLength(&velocity) * 4;
5091                             if (detail == 2)
5092                                 if (environment == snowyenvironment)
5093                                     for (j = 0; j < howmany; j++) {
5094                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5095                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5096                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5097                                         pos = coords;
5098                                         pos += velocity * .1;
5099                                         pos.y += 1;
5100                                         pos.x += float(abs(Random() % 100) - 50) / 150;
5101                                         pos.y += float(abs(Random() % 100) - 50) / 150;
5102                                         pos.z += float(abs(Random() % 100) - 50) / 150;
5103                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
5104                                         Sprite::setLastSpriteSpecial(2);
5105                                     }
5106                         }
5107                         objects.messedwith[i] = .5;
5108                     }
5109                 }
5110             }
5111
5112     if (!skeleton.free) {
5113         bool play;
5114         play = 0;
5115         if ((stunned > 0 || surprised > 0) && Person::players.size() > 2 && aitype != passivetype)
5116             play = 1;
5117         if (hasvictim)
5118             if (aitype != passivetype && victim->skeleton.free && !victim->dead)
5119                 play = 1;
5120         if (tutoriallevel == 1 && id != 0)
5121             play = 0;
5122         if (play && aitype != playercontrolled) {
5123             int whichsound = -1;
5124             i = abs(Random() % 4);
5125             if (speechdelay <= 0) {
5126                 if (creature == rabbittype) {
5127                     if (i == 0)
5128                         whichsound = rabbitchitter;
5129                     if (i == 1)
5130                         whichsound = rabbitchitter2;
5131                 }
5132                 if (creature == wolftype) {
5133                     if (i == 0)
5134                         whichsound = growlsound;
5135                     if (i == 1)
5136                         whichsound = growl2sound;
5137                 }
5138             }
5139             speechdelay = .3;
5140
5141             if (whichsound != -1) {
5142                 emit_sound_at(whichsound, coords);
5143             }
5144         }
5145
5146         if (animTarget == staggerbackhighanim)
5147             staggerdelay = 1;
5148         if (animTarget == staggerbackhardanim)
5149             staggerdelay = 1;
5150         staggerdelay -= multiplier;
5151         if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
5152             hasvictim = 1;
5153         if (velocity.y < -30 && animTarget == jumpdownanim)
5154             RagDoll(0);
5155         if (animCurrent != getIdle() && wasIdle() && animTarget != getIdle() && isIdle()) {
5156             animTarget = getIdle();
5157             frameTarget = 0;
5158             target = 0;
5159         }
5160         weaponmissdelay -= multiplier;
5161         highreversaldelay -= multiplier;
5162         lowreversaldelay -= multiplier;
5163         lastcollide -= multiplier;
5164         skiddelay -= multiplier;
5165         if (!isnormal(velocity.x) && velocity.x) {
5166             velocity = 0;
5167         }
5168         if (!isnormal(targettilt) && targettilt) {
5169             targettilt = 0;
5170         }
5171         if (!isnormal(targettilt2) && targettilt2) {
5172             targettilt2 = 0;
5173         }
5174         if (!isnormal(targetyaw) && targetyaw) {
5175             targetyaw = 0;
5176         }
5177
5178         if (animTarget == bounceidleanim || animTarget == wolfidle || animTarget == walkanim || animTarget == drawrightanim || animTarget == crouchdrawrightanim || animTarget == drawleftanim || animTarget == fightidleanim || animTarget == fightsidestep || animTarget == hanganim || isCrouch() || animTarget == backhandspringanim) {
5179             //open hands and close mouth
5180             if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
5181                 righthandmorphness = 0;
5182                 righthandmorphend = 0;
5183                 targetrighthandmorphness = 1;
5184             }
5185
5186             if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
5187                 lefthandmorphness = 0;
5188                 lefthandmorphend = 0;
5189                 targetlefthandmorphness = 1;
5190             }
5191
5192             if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5 && headmorphend != 0 && headmorphness == targetheadmorphness) {
5193                 headmorphness = 0;
5194                 headmorphend = 0;
5195                 targetheadmorphness = 1;
5196             }
5197         }
5198
5199         if (animTarget == rollanim || animTarget == dodgebackanim || animTarget == removeknifeanim || animTarget == knifefightidleanim || animTarget == swordfightidleanim || animTarget == blockhighleftstrikeanim || animTarget == crouchremoveknifeanim || animTarget == sneakanim || animTarget == sweepanim || animTarget == spinkickreversedanim || animTarget == jumpdownanim || isWallJump() || isFlip() || animTarget == climbanim || isRun() || animTarget == getupfrombackanim || animTarget == getupfromfrontanim) {
5200             //open hands and mouth
5201             if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
5202                 righthandmorphness = 0;
5203                 righthandmorphend = 0;
5204                 targetrighthandmorphness = 1;
5205             }
5206
5207             if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
5208                 lefthandmorphness = 0;
5209                 lefthandmorphend = 0;
5210                 targetlefthandmorphness = 1;
5211             }
5212
5213             if (headmorphend != 1 && headmorphness == targetheadmorphness) {
5214                 headmorphness = 0;
5215                 headmorphend = 1;
5216                 targetheadmorphness = 1;
5217             }
5218         }
5219
5220         if (animTarget == jumpupanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == swordfightidlebothanim || animTarget == blockhighleftanim) {
5221             //close hands and mouth
5222             if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
5223                 righthandmorphness = 0;
5224                 righthandmorphend = 1;
5225                 targetrighthandmorphness = 1;
5226             }
5227
5228             if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
5229                 lefthandmorphness = 0;
5230                 lefthandmorphend = 1;
5231                 targetlefthandmorphness = 1;
5232             }
5233
5234             if (headmorphend != 0 && headmorphness == targetheadmorphness) {
5235                 headmorphness = 0;
5236                 headmorphend = 0;
5237                 targetheadmorphness = 1;
5238             }
5239         }
5240
5241         if (animTarget == spinkickanim || animTarget == staffspinhitreversalanim || animTarget == staffspinhitreversedanim || animTarget == staffhitreversalanim || animTarget == staffhitreversedanim || animTarget == hurtidleanim || animTarget == winduppunchanim || animTarget == swordslashreversalanim || animTarget == swordslashreversedanim || animTarget == knifeslashreversalanim || animTarget == knifeslashreversedanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == knifefollowedanim || animTarget == killanim || animTarget == dropkickanim || animTarget == upunchanim || animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim || animTarget == staffgroundsmashanim || animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == lowkickanim || animTarget == sweepreversedanim || animTarget == rabbitkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversalanim || animTarget == jumpreversedanim) {
5242             //close hands and yell
5243             if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
5244                 righthandmorphness = 0;
5245                 righthandmorphend = 1;
5246                 targetrighthandmorphness = 1;
5247             }
5248
5249             if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
5250                 lefthandmorphness = 0;
5251                 lefthandmorphend = 1;
5252                 targetlefthandmorphness = 1;
5253             }
5254
5255             if (headmorphend != 2 && headmorphness == targetheadmorphness) {
5256                 headmorphness = 1;
5257                 headmorphend = 2;
5258                 targetheadmorphness = 1;
5259             }
5260         }
5261
5262         bool behind;
5263         behind = 0;
5264         if (hasvictim) {
5265             if ((victim != this->shared_from_this()) && !victim->dead && (victim->aitype != passivetype) &&
5266                 (victim->aitype != searchtype) && (aitype != passivetype) &&
5267                 (aitype != searchtype) && (victim->id < Person::players.size())) {
5268                 behind = (normaldotproduct(facing, coords - victim->coords) > 0);
5269             }
5270         }
5271
5272         if (!dead && animTarget != hurtidleanim)
5273             if (behind || animTarget == killanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == spinkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversedanim) {
5274                 if (headmorphend != 4 || headmorphness == targetheadmorphness) {
5275                     headmorphend = 4;
5276                     //headmorphness=1;
5277                     targetheadmorphness = 1;
5278                 }
5279             }
5280
5281         if (weaponactive != -1) {
5282             if (weapons[weaponids[weaponactive]].getType() != staff) {
5283                 righthandmorphstart = 1;
5284                 righthandmorphend = 1;
5285             }
5286             if (weapons[weaponids[weaponactive]].getType() == staff) {
5287                 righthandmorphstart = 2;
5288                 righthandmorphend = 2;
5289             }
5290             targetrighthandmorphness = 1;
5291         }
5292
5293         terrainnormal = terrain.getNormal(coords.x, coords.z);
5294
5295         if (animation[animTarget].attack != reversal) {
5296             if (!isnormal(coords.x))
5297                 coords = oldcoords;
5298             oldcoords = coords;
5299         }
5300
5301         flatfacing = 0;
5302         flatfacing.z = 1;
5303
5304         flatfacing = DoRotation(flatfacing, 0, yaw, 0);
5305         facing = flatfacing;
5306         ReflectVector(&facing, terrainnormal);
5307         Normalise(&facing);
5308
5309         if (isRun() || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim) {
5310             if (onterrain)
5311                 targettilt2 = -facing.y * 20;
5312             else
5313                 targettilt2 = 0;
5314         }
5315         onterrain = 0;
5316         if (!isRun() && !animation[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim)
5317             targettilt2 = 0;
5318         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
5319             flatvelocity = velocity;
5320             flatvelocity.y = 0;
5321             flatvelspeed = findLength(&flatvelocity);
5322             targettilt = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(DoRotation(flatfacing, 0, -90, 0), flatvelocity);
5323             targettilt2 = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(flatfacing, flatvelocity);
5324             if (velocity.y < 0)
5325                 targettilt2 *= -1;
5326             if (velocity.y < 0)
5327                 targettilt *= -1;
5328             if (targettilt > 25)
5329                 targettilt = 25;
5330             if (targettilt < -25)
5331                 targettilt = -25;
5332         }
5333
5334         if (targettilt2 > 45)
5335             targettilt2 = 45;
5336         if (targettilt2 < -45)
5337             targettilt2 = -45;
5338         if (abs(tilt2 - targettilt2) < multiplier * 400)
5339             tilt2 = targettilt2;
5340         else if (tilt2 > targettilt2) {
5341             tilt2 -= multiplier * 400;
5342         } else if (tilt2 < targettilt2) {
5343             tilt2 += multiplier * 400;
5344         }
5345         if (!animation[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
5346             if (tilt2 > 25)
5347                 tilt2 = 25;
5348             if (tilt2 < -25)
5349                 tilt2 = -25;
5350         }
5351
5352         if (!isnormal(targettilt) && targettilt) {
5353             targettilt = 0;
5354         }
5355         if (!isnormal(targettilt2) && targettilt2) {
5356             targettilt2 = 0;
5357         }
5358
5359         //Running velocity
5360         if (animTarget == rabbittackleanim) {
5361             velocity += facing * multiplier * speed * 700 * scale;
5362             velspeed = findLength(&velocity);
5363             if (velspeed > speed * 65 * scale) {
5364                 velocity /= velspeed;
5365                 velspeed = speed * 65 * scale;
5366                 velocity *= velspeed;
5367             }
5368             velocity.y += gravity * multiplier * 20;
5369             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5370             velspeed = findLength(&velocity);
5371             velocity = flatfacing * velspeed;
5372         }
5373         if (animTarget != rabbitrunninganim && animTarget != wolfrunninganim) {
5374             if (isRun() || animTarget == rabbitkickanim) {
5375                 velocity += facing * multiplier * speed * 700 * scale;
5376                 velspeed = findLength(&velocity);
5377                 if (velspeed > speed * 45 * scale) {
5378                     velocity /= velspeed;
5379                     velspeed = speed * 45 * scale;
5380                     velocity *= velspeed;
5381                 }
5382                 velocity.y += gravity * multiplier * 20;
5383                 ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5384                 velspeed = findLength(&velocity);
5385                 if (velspeed < speed * 30 * scale)
5386                     velspeed = speed * 30 * scale;
5387                 velocity = flatfacing * velspeed;
5388             }
5389         } else if (isRun()) {
5390             velocity += facing * multiplier * speed * 700 * scale;
5391             velspeed = findLength(&velocity);
5392             if (creature == rabbittype) {
5393                 if (velspeed > speed * 55 * scale) {
5394                     velocity /= velspeed;
5395                     velspeed = speed * 55 * scale;
5396                     velocity *= velspeed;
5397                 }
5398             }
5399             if (creature == wolftype) {
5400                 if (velspeed > speed * 75 * scale) {
5401                     velocity /= velspeed;
5402                     velspeed = speed * 75 * scale;
5403                     velocity *= velspeed;
5404                 }
5405             }
5406             velocity.y += gravity * multiplier * 20;
5407             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5408             velspeed = findLength(&velocity);
5409             velocity = flatfacing * velspeed;
5410         }
5411
5412         if (animTarget == rollanim && animation[animTarget].label[frameTarget] != 6) {
5413             velocity += facing * multiplier * speed * 700 * scale;
5414             velspeed = findLength(&velocity);
5415             if (velspeed > speed * 45 * scale) {
5416                 velocity /= velspeed;
5417                 velspeed = speed * 45 * scale;
5418                 velocity *= velspeed;
5419             }
5420             velocity.y += gravity * multiplier * 20;
5421             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5422             velspeed = findLength(&velocity);
5423             velocity = flatfacing * velspeed;
5424         }
5425
5426         if (animTarget == sneakanim || animTarget == walkanim) {
5427             velocity += facing * multiplier * speed * 700 * scale;
5428             velspeed = findLength(&velocity);
5429             if (velspeed > speed * 12 * scale) {
5430                 velocity /= velspeed;
5431                 velspeed = speed * 12 * scale;
5432                 velocity *= velspeed;
5433             }
5434             velocity.y += gravity * multiplier * 20;
5435             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5436             velspeed = findLength(&velocity);
5437             velocity = flatfacing * velspeed;
5438         }
5439
5440         if ((animTarget == fightidleanim || animTarget == knifefightidleanim) && (animCurrent == bounceidleanim || animCurrent == hurtidleanim)) {
5441             velocity += facing * multiplier * speed * 700 * scale;
5442             velspeed = findLength(&velocity);
5443             if (velspeed > speed * 2 * scale) {
5444                 velocity /= velspeed;
5445                 velspeed = speed * 2 * scale;
5446                 velocity *= velspeed;
5447             }
5448             velocity.y += gravity * multiplier * 20;
5449             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5450             velspeed = findLength(&velocity);
5451             velocity = flatfacing * velspeed;
5452         }
5453
5454
5455         if ((animTarget == bounceidleanim || animCurrent == hurtidleanim) && (animCurrent == fightidleanim || animCurrent == knifefightidleanim)) {
5456             velocity -= facing * multiplier * speed * 700 * scale;
5457             velspeed = findLength(&velocity);
5458             if (velspeed > speed * 2 * scale) {
5459                 velocity /= velspeed;
5460                 velspeed = speed * 2 * scale;
5461                 velocity *= velspeed;
5462             }
5463             velocity.y += gravity * multiplier * 20;
5464             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5465             velspeed = findLength(&velocity);
5466             velocity = flatfacing * velspeed * -1;
5467         }
5468
5469         if (animTarget == fightsidestep) {
5470             velocity += DoRotation(facing * multiplier * speed * 700 * scale, 0, -90, 0);
5471             velspeed = findLength(&velocity);
5472             if (velspeed > speed * 12 * scale) {
5473                 velocity /= velspeed;
5474                 velspeed = speed * 12 * scale;
5475                 velocity *= velspeed;
5476             }
5477             velocity.y += gravity * multiplier * 20;
5478             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5479             velspeed = findLength(&velocity);
5480             velocity = DoRotation(flatfacing * velspeed, 0, -90, 0);
5481         }
5482
5483         if (animTarget == staggerbackhighanim) {
5484             coords -= facing * multiplier * speed * 16 * scale;
5485             velocity = 0;
5486         }
5487         if (animTarget == staggerbackhardanim && animation[staggerbackhardanim].label[frameTarget] != 6) {
5488             coords -= facing * multiplier * speed * 20 * scale;
5489             velocity = 0;
5490         }
5491
5492         if (animTarget == backhandspringanim) {
5493             //coords-=facing*multiplier*50*scale;
5494             velocity += facing * multiplier * speed * 700 * scale * -1;
5495             velspeed = findLength(&velocity);
5496             if (velspeed > speed * 50 * scale) {
5497                 velocity /= velspeed;
5498                 velspeed = speed * 50 * scale;
5499                 velocity *= velspeed;
5500             }
5501             velocity.y += gravity * multiplier * 20;
5502             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5503             velspeed = findLength(&velocity);
5504             velocity = flatfacing * velspeed * -1;
5505         }
5506         if (animTarget == dodgebackanim) {
5507             //coords-=facing*multiplier*50*scale;
5508             velocity += facing * multiplier * speed * 700 * scale * -1;
5509             velspeed = findLength(&velocity);
5510             if (velspeed > speed * 60 * scale) {
5511                 velocity /= velspeed;
5512                 velspeed = speed * 60 * scale;
5513                 velocity *= velspeed;
5514             }
5515             velocity.y += gravity * multiplier * 20;
5516             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
5517             velspeed = findLength(&velocity);
5518             velocity = flatfacing * velspeed * -1;
5519         }
5520
5521         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
5522             velspeed = findLength(&velocity);
5523         }
5524
5525
5526         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
5527             velocity.y += gravity * multiplier;
5528         }
5529
5530         if (animTarget != climbanim && animTarget != hanganim && !isWallJump())
5531             coords += velocity * multiplier;
5532
5533         if (coords.y < terrain.getHeight(coords.x, coords.z) && (animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
5534             if (isFlip() && animation[animTarget].label[frameTarget] == 7)
5535                 RagDoll(0);
5536
5537             if (animTarget == jumpupanim) {
5538                 jumppower = -4;
5539                 animTarget = getIdle();
5540             }
5541             target = 0;
5542             frameTarget = 0;
5543             onterrain = 1;
5544
5545             if (id == 0) {
5546                 pause_sound(whooshsound);
5547                 OPENAL_SetVolume(channels[whooshsound], 0);
5548             }
5549
5550             if (animTarget == jumpdownanim || isFlip()) {
5551                 if (isFlip())jumppower = -4;
5552                 animTarget = getLanding();
5553                 emit_sound_at(landsound, coords, 128.);
5554
5555                 if (id == 0) {
5556                     envsound[numenvsounds] = coords;
5557                     envsoundvol[numenvsounds] = 16;
5558                     envsoundlife[numenvsounds] = .4;
5559                     numenvsounds++;
5560                 }
5561             }
5562         }
5563
5564         if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && animTarget != climbanim && animTarget != hanganim && !isWallJump())
5565             coords.y += gravity * multiplier * 2;
5566         if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && coords.y < terrain.getHeight(coords.x, coords.z)) {
5567             coords.y = terrain.getHeight(coords.x, coords.z);
5568             onterrain = 1;
5569         }
5570
5571
5572         if (isIdle() || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || isStop() || animTarget == removeknifeanim || animTarget == crouchremoveknifeanim || isLanding() || isCrouch() || animation[animTarget].attack || (animTarget == rollanim && animation[animTarget].label[frameTarget] == 6)) {
5573             velspeed = findLength(&velocity);
5574             velocity.y = 0;
5575             if (velspeed < multiplier * 300 * scale) {
5576                 velocity = 0;
5577             } else
5578                 velocity -= velocity / velspeed * multiplier * 300 * scale;
5579             if (velspeed > 5 && (isLanding() || isLandhard())) {
5580                 skiddingdelay += multiplier;
5581                 if (skiddelay <= 0) {
5582                     FootLand(0, .5);
5583                     FootLand(1, .5);
5584                     skiddelay = .02;
5585                 }
5586             } else
5587                 skiddingdelay = 0;
5588         }
5589
5590         if (isLandhard()) {
5591             velspeed = findLength(&velocity);
5592             velocity.y = 0;
5593             if (velspeed < multiplier * 600 * scale) {
5594                 velocity = 0;
5595             } else
5596                 velocity -= velocity / velspeed * multiplier * 600 * scale;
5597             velocity = 0;
5598             if (velspeed > 5 && (isLanding() || isLandhard())) {
5599                 skiddingdelay += multiplier;
5600                 if (skiddelay <= 0) {
5601                     FootLand(0, .5);
5602                     FootLand(1, .5);
5603                     skiddelay = .02;
5604                 }
5605             } else
5606                 skiddingdelay = 0;
5607         }
5608
5609         if (skiddingdelay < 0)
5610             skiddingdelay += multiplier;
5611         if (skiddingdelay > .02 && !forwardkeydown && !backkeydown && !leftkeydown && !rightkeydown && !jumpkeydown && isLanding() && !landhard) {
5612             skiddingdelay = -1;
5613             if (!onterrain || environment == grassyenvironment) {
5614                 emit_sound_at(skidsound, coords, 128 * velspeed / 10);
5615             } else {
5616                 emit_sound_at(snowskidsound, coords, 128 * velspeed / 10);
5617             }
5618         }
5619
5620         if (animation[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
5621             terrainnormal = victim->coords - coords;
5622             Normalise(&terrainnormal);
5623             targetyaw = -asin(0 - terrainnormal.x);
5624             targetyaw *= 360 / 6.28;
5625             if (terrainnormal.z < 0)
5626                 targetyaw = 180 - targetyaw;
5627             targettilt2 = -asin(terrainnormal.y) * 360 / 6.28; //*-70;
5628         }
5629
5630         if (animation[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
5631             targetyaw = victim->targetyaw;
5632         }
5633         if (animTarget == rabbittacklinganim) {
5634             coords = victim->coords;
5635         }
5636     }
5637     skeleton.oldfree = skeleton.free;
5638
5639     XYZ midterrain;
5640     midterrain = 0;
5641     midterrain.x = terrain.size * terrain.scale / 2;
5642     midterrain.z = terrain.size * terrain.scale / 2;
5643     if (distsqflat(&coords, &midterrain) > (terrain.size * terrain.scale / 2 - viewdistance) * (terrain.size * terrain.scale / 2 - viewdistance)) {
5644         XYZ tempposit;
5645         tempposit = coords - midterrain;
5646         tempposit.y = 0;
5647         Normalise(&tempposit);
5648         tempposit *= (terrain.size * terrain.scale / 2 - viewdistance);
5649         coords.x = tempposit.x + midterrain.x;
5650         coords.z = tempposit.z + midterrain.z;
5651     }
5652 }
5653
5654
5655 /* EFFECT
5656  * inverse kinematics helper function
5657  */
5658 void IKHelper(Person *p, float interp)
5659 {
5660     XYZ point, change, change2;
5661     float heightleft, heightright;
5662
5663     // TODO: implement localToWorld and worldToLocal
5664     //       but keep in mind it won't be the same math if player is ragdolled or something
5665     //       - localToWorldStanding / worldToLocalStanding (or crouching or...?)
5666     //       then comb through code for places where to use it
5667
5668     // point = localToWorld(jointPos(leftfoot))
5669     point = DoRotation(p->jointPos(leftfoot), 0, p->yaw, 0) * p->scale + p->coords;
5670     // adjust height of foot
5671     heightleft = terrain.getHeight(point.x, point.z) + .04;
5672     point.y = heightleft;
5673     change = p->jointPos(leftankle) - p->jointPos(leftfoot);
5674     change2 = p->jointPos(leftknee) - p->jointPos(leftfoot);
5675     // jointPos(leftfoot) = interpolate(worldToLocal(point), jointPos(leftfoot), interp)
5676     p->jointPos(leftfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(leftfoot) * (1 - interp);
5677     // move ankle along with foot
5678     p->jointPos(leftankle) = p->jointPos(leftfoot) + change;
5679     // average knee pos between old and new pos
5680     p->jointPos(leftknee) = (p->jointPos(leftfoot) + change2) / 2 + (p->jointPos(leftknee)) / 2;
5681
5682     // do same as above for right leg
5683     point = DoRotation(p->jointPos(rightfoot), 0, p->yaw, 0) * p->scale + p->coords;
5684     heightright = terrain.getHeight(point.x, point.z) + .04;
5685     point.y = heightright;
5686     change = p->jointPos(rightankle) - p->jointPos(rightfoot);
5687     change2 = p->jointPos(rightknee) - p->jointPos(rightfoot);
5688     p->jointPos(rightfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(rightfoot) * (1 - interp);
5689     p->jointPos(rightankle) = p->jointPos(rightfoot) + change;
5690     p->jointPos(rightknee) = (p->jointPos(rightfoot) + change2) / 2 + (p->jointPos(rightknee)) / 2;
5691
5692     // fix up skeleton now that we've moved body parts?
5693     p->skeleton.DoConstraints(&p->coords, &p->scale);
5694 }
5695
5696 /* EFFECT
5697  * MONSTER
5698  * TODO: ???
5699  */
5700 int Person::DrawSkeleton()
5701 {
5702     int oldplayerdetail;
5703     if ((frustum.SphereInFrustum(coords.x, coords.y + scale * 3, coords.z, scale * 8) && distsq(&viewer, &coords) < viewdistance * viewdistance) || skeleton.free == 3) {
5704         if (onterrain && (isIdle() || isCrouch() || wasIdle() || wasCrouch()) && !skeleton.free) {
5705             calcrot = 1;
5706         }
5707
5708         if (headless) {
5709             headmorphness = 0;
5710             headmorphstart = 6;
5711             headmorphend = 6;
5712         }
5713
5714         glAlphaFunc(GL_GREATER, 0.0001);
5715         XYZ terrainlight;
5716         float terrainheight;
5717         float distance;
5718         if (!isnormal(yaw))
5719             yaw = 0;
5720         if (!isnormal(tilt))
5721             tilt = 0;
5722         if (!isnormal(tilt2))
5723             tilt2 = 0;
5724         oldplayerdetail = playerdetail;
5725         playerdetail = 0;
5726         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 32 && detail == 2) {
5727             playerdetail = 1;
5728         }
5729         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 128 && detail == 1) {
5730             playerdetail = 1;
5731         }
5732         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 256 && (detail != 1 && detail != 2)) {
5733             playerdetail = 1;
5734         }
5735         if (id == 0)
5736             playerdetail = 1;
5737         if (playerdetail != oldplayerdetail) {
5738             updatedelay = 0;
5739             normalsupdatedelay = 0;
5740         }
5741         static float updatedelaychange;
5742         static float morphness;
5743         static float framemult;
5744         if (calcrot) {
5745             skeleton.FindForwards();
5746             if (howactive == typesittingwall) {
5747                 skeleton.specialforward[1] = 0;
5748                 skeleton.specialforward[1].z = 1;
5749             }
5750         }
5751         static XYZ mid;
5752         static float M[16];
5753         static int i, j, k;
5754         static int weaponattachmuscle;
5755         static int weaponrotatemuscle;
5756         static XYZ weaponpoint;
5757         static int start, endthing;
5758         if ((dead != 2 || skeleton.free != 2) && updatedelay <= 0) {
5759             if (!isSleeping() && !isSitting()) {
5760                 // TODO: give these meaningful names
5761                 const bool cond1 = (isIdle() || isCrouch() || isLanding() || isLandhard()
5762                                     || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim);
5763                 const bool cond2 = (wasIdle() || wasCrouch() || wasLanding() || wasLandhard()
5764                                     || animCurrent == drawrightanim || animCurrent == drawleftanim || animCurrent == crouchdrawrightanim);
5765
5766                 if (onterrain && (cond1 && cond2) && !skeleton.free) {
5767                     IKHelper(this, 1);
5768                     if (creature == wolftype)
5769                         IKHelper(this, 1);
5770                 }
5771
5772                 if (onterrain && (cond1 && !cond2) && !skeleton.free) {
5773                     IKHelper(this, target);
5774                     if (creature == wolftype)
5775                         IKHelper(this, target);
5776                 }
5777
5778                 if (onterrain && (!cond1 && cond2) && !skeleton.free) {
5779                     IKHelper(this, 1 - target);
5780                     if (creature == wolftype)
5781                         IKHelper(this, 1 - target);
5782                 }
5783             }
5784
5785             if (!skeleton.free && (!animation[animTarget].attack && animTarget != getupfrombackanim && ((animTarget != rollanim && !isFlip()) || animation[animTarget].label[frameTarget] == 6) && animTarget != getupfromfrontanim && animTarget != wolfrunninganim && animTarget != rabbitrunninganim && animTarget != backhandspringanim && animTarget != walljumpfrontanim && animTarget != hurtidleanim && !isLandhard() && !isSleeping()))
5786                 DoHead();
5787             else {
5788                 targetheadyaw = -targetyaw;
5789                 targetheadpitch = 0;
5790                 if (animation[animTarget].attack == 3)
5791                     targetheadyaw += 180;
5792             }
5793             for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
5794                 skeleton.drawmodel.vertex[i] = 0;
5795                 skeleton.drawmodel.vertex[i].y = 999;
5796             }
5797             for (i = 0; i < skeleton.drawmodellow.vertexNum; i++) {
5798                 skeleton.drawmodellow.vertex[i] = 0;
5799                 skeleton.drawmodellow.vertex[i].y = 999;
5800             }
5801             for (i = 0; i < skeleton.drawmodelclothes.vertexNum; i++) {
5802                 skeleton.drawmodelclothes.vertex[i] = 0;
5803                 skeleton.drawmodelclothes.vertex[i].y = 999;
5804             }
5805             for (int i = 0; i < skeleton.num_muscles; i++) {
5806                 // convenience renames
5807                 const int p1 = skeleton.muscles[i].parent1->label;
5808                 const int p2 = skeleton.muscles[i].parent2->label;
5809
5810                 if ((skeleton.muscles[i].numvertices > 0 && playerdetail) || (skeleton.muscles[i].numverticeslow > 0 && !playerdetail)) {
5811                     morphness = 0;
5812                     start = 0;
5813                     endthing = 0;
5814
5815                     if (p1 == righthand || p2 == righthand) {
5816                         morphness = righthandmorphness;
5817                         start = righthandmorphstart;
5818                         endthing = righthandmorphend;
5819                     }
5820                     if (p1 == lefthand || p2 == lefthand) {
5821                         morphness = lefthandmorphness;
5822                         start = lefthandmorphstart;
5823                         endthing = lefthandmorphend;
5824                     }
5825                     if (p1 == head || p2 == head) {
5826                         morphness = headmorphness;
5827                         start = headmorphstart;
5828                         endthing = headmorphend;
5829                     }
5830                     if ((p1 == neck && p2 == abdomen) || (p2 == neck && p1 == abdomen)) {
5831                         morphness = chestmorphness;
5832                         start = chestmorphstart;
5833                         endthing = chestmorphend;
5834                     }
5835                     if ((p1 == groin && p2 == abdomen) || (p2 == groin && p1 == abdomen)) {
5836                         morphness = tailmorphness;
5837                         start = tailmorphstart;
5838                         endthing = tailmorphend;
5839                     }
5840                     if (calcrot)
5841                         skeleton.FindRotationMuscle(i, animTarget);
5842                     mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
5843                     glMatrixMode(GL_MODELVIEW);
5844                     glPushMatrix();
5845                     glLoadIdentity();
5846                     if (!skeleton.free)
5847                         glRotatef(tilt2, 1, 0, 0);
5848                     if (!skeleton.free)
5849                         glRotatef(tilt, 0, 0, 1);
5850
5851
5852                     glTranslatef(mid.x, mid.y, mid.z);
5853
5854                     skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
5855                     glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
5856
5857                     skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
5858                     glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
5859
5860                     skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
5861                     glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
5862
5863                     if (playerdetail || skeleton.free == 3) {
5864                         for (j = 0; j < skeleton.muscles[i].numvertices; j++) {
5865                             XYZ &v0 = skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]];
5866                             XYZ &v1 = skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]];
5867                             glMatrixMode(GL_MODELVIEW);
5868                             glPushMatrix();
5869                             if (p1 == abdomen || p2 == abdomen)
5870                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionbody.x,
5871                                              (v0.y * (1 - morphness) + v1.y * morphness) * proportionbody.y,
5872                                              (v0.z * (1 - morphness) + v1.z * morphness) * proportionbody.z);
5873                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
5874                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionarms.x,
5875                                              (v0.y * (1 - morphness) + v1.y * morphness) * proportionarms.y,
5876                                              (v0.z * (1 - morphness) + v1.z * morphness) * proportionarms.z);
5877                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
5878                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionlegs.x,
5879                                              (v0.y * (1 - morphness) + v1.y * morphness) * proportionlegs.y,
5880                                              (v0.z * (1 - morphness) + v1.z * morphness) * proportionlegs.z);
5881                             if (p1 == head || p2 == head)
5882                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionhead.x,
5883                                              (v0.y * (1 - morphness) + v1.y * morphness) * proportionhead.y,
5884                                              (v0.z * (1 - morphness) + v1.z * morphness) * proportionhead.z);
5885                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
5886                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x = M[12] * scale;
5887                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].y = M[13] * scale;
5888                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].z = M[14] * scale;
5889                             glPopMatrix();
5890                         }
5891                     }
5892                     if (!playerdetail || skeleton.free == 3) {
5893                         for (j = 0; j < skeleton.muscles[i].numverticeslow; j++) {
5894                             XYZ &v0 = skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]];
5895                             glMatrixMode(GL_MODELVIEW);
5896                             glPushMatrix();
5897                             if (p1 == abdomen || p2 == abdomen)
5898                                 glTranslatef(v0.x * proportionbody.x,
5899                                              v0.y * proportionbody.y,
5900                                              v0.z * proportionbody.z);
5901                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
5902                                 glTranslatef(v0.x * proportionarms.x,
5903                                              v0.y * proportionarms.y,
5904                                              v0.z * proportionarms.z);
5905                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
5906                                 glTranslatef(v0.x * proportionlegs.x,
5907                                              v0.y * proportionlegs.y,
5908                                              v0.z * proportionlegs.z);
5909                             if (p1 == head || p2 == head)
5910                                 glTranslatef(v0.x * proportionhead.x,
5911                                              v0.y * proportionhead.y,
5912                                              v0.z * proportionhead.z);
5913
5914                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
5915                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].x = M[12] * scale;
5916                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].y = M[13] * scale;
5917                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].z = M[14] * scale;
5918                             glPopMatrix();
5919                         }
5920                     }
5921                     glPopMatrix();
5922                 }
5923                 if (skeleton.clothes && skeleton.muscles[i].numverticesclothes > 0) {
5924                     mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
5925
5926                     glMatrixMode(GL_MODELVIEW);
5927                     glPushMatrix();
5928                     glLoadIdentity();
5929                     if (!skeleton.free)
5930                         glRotatef(tilt2, 1, 0, 0);
5931                     if (!skeleton.free)
5932                         glRotatef(tilt, 0, 0, 1);
5933                     glTranslatef(mid.x, mid.y, mid.z);
5934                     skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
5935                     glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
5936
5937                     skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
5938                     glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
5939
5940                     skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
5941                     glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
5942
5943                     for (j = 0; j < skeleton.muscles[i].numverticesclothes; j++) {
5944                         XYZ &v0 = skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]];
5945                         glMatrixMode(GL_MODELVIEW);
5946                         glPushMatrix();
5947                         if (p1 == abdomen || p2 == abdomen)
5948                             glTranslatef(v0.x * proportionbody.x,
5949                                          v0.y * proportionbody.y,
5950                                          v0.z * proportionbody.z);
5951                         if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
5952                             glTranslatef(v0.x * proportionarms.x,
5953                                          v0.y * proportionarms.y,
5954                                          v0.z * proportionarms.z);
5955                         if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
5956                             glTranslatef(v0.x * proportionlegs.x,
5957                                          v0.y * proportionlegs.y,
5958                                          v0.z * proportionlegs.z);
5959                         if (p1 == head || p2 == head)
5960                             glTranslatef(v0.x * proportionhead.x,
5961                                          v0.y * proportionhead.y,
5962                                          v0.z * proportionhead.z);
5963                         glGetFloatv(GL_MODELVIEW_MATRIX, M);
5964                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x = M[12] * scale;
5965                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y = M[13] * scale;
5966                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z = M[14] * scale;
5967                         glPopMatrix();
5968                     }
5969                     glPopMatrix();
5970                 }
5971                 updatedelay = 1 + (float)(Random() % 100) / 1000;
5972             }
5973             if (skeleton.free != 2 && (skeleton.free == 1 || skeleton.free == 3 || id == 0 || (normalsupdatedelay <= 0) || animTarget == getupfromfrontanim || animTarget == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == getupfrombackanim)) {
5974                 normalsupdatedelay = 1;
5975                 if (playerdetail || skeleton.free == 3)
5976                     skeleton.drawmodel.CalculateNormals(0);
5977                 if (!playerdetail || skeleton.free == 3)
5978                     skeleton.drawmodellow.CalculateNormals(0);
5979                 if (skeleton.clothes)
5980                     skeleton.drawmodelclothes.CalculateNormals(0);
5981             } else {
5982                 if (playerdetail || skeleton.free == 3)
5983                     skeleton.drawmodel.UpdateVertexArrayNoTexNoNorm();
5984                 if (!playerdetail || skeleton.free == 3)
5985                     skeleton.drawmodellow.UpdateVertexArrayNoTexNoNorm();
5986                 if (skeleton.clothes) {
5987                     skeleton.drawmodelclothes.UpdateVertexArrayNoTexNoNorm();
5988                 }
5989             }
5990         }
5991         framemult = .01;
5992         updatedelaychange = -framemult * 4 * (45 - findDistance(&viewer, &coords) * 1);
5993         if (updatedelaychange > -realmultiplier * 30)
5994             updatedelaychange = -realmultiplier * 30;
5995         if (updatedelaychange > -framemult * 4)
5996             updatedelaychange = -framemult * 4;
5997         if (skeleton.free == 1)
5998             updatedelaychange *= 6;
5999         if (id == 0)
6000             updatedelaychange *= 8;
6001         updatedelay += updatedelaychange;
6002
6003         glMatrixMode(GL_MODELVIEW);
6004         glPushMatrix();
6005         glTranslatef(coords.x, coords.y - .02, coords.z);
6006         if (!skeleton.free) {
6007             glTranslatef(offset.x * scale, offset.y * scale, offset.z * scale);
6008             glRotatef(yaw, 0, 1, 0);
6009         }
6010         if (showpoints) {
6011             glPointSize(5);
6012             glColor4f(.4, 1, .4, 1);
6013             glDisable(GL_LIGHTING);
6014             glDisable(GL_TEXTURE_2D);
6015             glBegin(GL_POINTS);
6016             if (playerdetail)
6017                 for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
6018                     XYZ &v0 = skeleton.drawmodel.vertex[i];
6019                     glVertex3f(v0.x, v0.y, v0.z);
6020                 }
6021             glEnd();
6022             glBegin(GL_LINES);
6023
6024             if (playerdetail)
6025                 for (i = 0; i < skeleton.drawmodel.TriangleNum; i++) {
6026                     XYZ &v0 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]];
6027                     XYZ &v1 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]];
6028                     XYZ &v2 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]];
6029                     glVertex3f(v0.x, v0.y, v0.z);
6030                     glVertex3f(v1.x, v1.y, v1.z);
6031                     glVertex3f(v1.x, v1.y, v1.z);
6032                     glVertex3f(v2.x, v2.y, v2.z);
6033                     glVertex3f(v2.x, v2.y, v2.z);
6034                     glVertex3f(v0.x, v0.y, v0.z);
6035                 }
6036
6037             glEnd();
6038         }
6039
6040         terrainlight = terrain.getLighting(coords.x, coords.z);
6041         distance = distsq(&viewer, &coords);
6042         distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
6043         if (distance > 1)
6044             distance = 1;
6045         if (distance > 0) {
6046             terrainheight = (coords.y - terrain.getHeight(coords.x, coords.z)) / 3 + 1;
6047             if (terrainheight < 1)
6048                 terrainheight = 1;
6049             if (terrainheight > 1.7)
6050                 terrainheight = 1.7;
6051
6052             //burnt=0;
6053             glColor4f((1 - (1 - terrainlight.x) / terrainheight) - burnt, (1 - (1 - terrainlight.y) / terrainheight) - burnt, (1 - (1 - terrainlight.z) / terrainheight) - burnt, distance);
6054             glDisable(GL_BLEND);
6055             glAlphaFunc(GL_GREATER, 0.0001);
6056             glEnable(GL_TEXTURE_2D);
6057             if (cellophane) {
6058                 glDisable(GL_TEXTURE_2D);
6059                 glColor4f(.7, .35, 0, .5);
6060                 glDepthMask(0);
6061                 glEnable(GL_LIGHTING);
6062                 glEnable(GL_BLEND);
6063             }
6064             if (tutoriallevel && id != 0) {
6065                 glColor4f(.7, .7, .7, 0.6);
6066                 glDepthMask(0);
6067                 glEnable(GL_LIGHTING);
6068                 glEnable(GL_BLEND);
6069                 if (canattack && cananger)
6070                     if (animation[animTarget].attack == normalattack || animation[animTarget].attack == reversed) {
6071                         glDisable(GL_TEXTURE_2D);
6072                         glColor4f(1, 0, 0, 0.8);
6073                     }
6074                 glMatrixMode(GL_TEXTURE);
6075                 glPushMatrix();
6076                 glTranslatef(0, -smoketex, 0);
6077                 glTranslatef(-smoketex, 0, 0);
6078             }
6079             if (playerdetail) {
6080                 if (!showpoints) {
6081                     if ((tutoriallevel && id != 0))
6082                         skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
6083                     else
6084                         skeleton.drawmodel.draw();
6085                 }
6086             }
6087             if (!playerdetail) {
6088                 if ((tutoriallevel && id != 0))
6089                     skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
6090                 else
6091                     skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
6092             }
6093
6094             if (!(animation[animTarget].attack == normalattack || animation[animTarget].attack == reversed))
6095                 if (tutoriallevel && id != 0) {
6096                     glPopMatrix();
6097                     glMatrixMode(GL_MODELVIEW);
6098                     glEnable(GL_TEXTURE_2D);
6099                     glColor4f(.7, .7, .7, 0.6);
6100                     glDepthMask(0);
6101                     glEnable(GL_LIGHTING);
6102                     glEnable(GL_BLEND);
6103                     if (canattack && cananger)
6104                         if (animation[animTarget].attack == normalattack || animation[animTarget].attack == reversed) {
6105                             glDisable(GL_TEXTURE_2D);
6106                             glColor4f(1, 0, 0, 0.8);
6107                         }
6108                     glMatrixMode(GL_TEXTURE);
6109                     glPushMatrix();
6110                     glTranslatef(0, -smoketex * .6, 0);
6111                     glTranslatef(smoketex * .6, 0, 0);
6112                     if (playerdetail) {
6113                         if (!showpoints) {
6114                             if ((tutoriallevel && id != 0))
6115                                 skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
6116                             else
6117                                 skeleton.drawmodel.draw();
6118                         }
6119                     }
6120                     if (!playerdetail) {
6121                         if ((tutoriallevel && id != 0))
6122                             skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
6123                         else
6124                             skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
6125                     }
6126                 }
6127
6128
6129             if (tutoriallevel && id != 0) {
6130                 glPopMatrix();
6131                 glMatrixMode(GL_MODELVIEW);
6132                 glEnable(GL_TEXTURE_2D);
6133             }
6134             if (skeleton.clothes) {
6135                 glDepthMask(0);
6136                 glEnable(GL_BLEND);
6137                 if (!immediate)
6138                     skeleton.drawmodelclothes.draw();
6139                 if (immediate)
6140                     skeleton.drawmodelclothes.drawimmediate();
6141                 glDepthMask(1);
6142             }
6143         }
6144         glPopMatrix();
6145
6146         if (num_weapons > 0) {
6147             for (k = 0; k < num_weapons; k++) {
6148                 i = weaponids[k];
6149                 if (weaponactive == k) {
6150                     if (weapons[i].getType() != staff) {
6151                         for (j = 0; j < skeleton.num_muscles; j++) {
6152                             if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].numvertices > 0) {
6153                                 weaponattachmuscle = j;
6154                             }
6155                         }
6156                         for (j = 0; j < skeleton.num_muscles; j++) {
6157                             if ((skeleton.muscles[j].parent1->label == rightwrist || skeleton.muscles[j].parent2->label == rightwrist) && (skeleton.muscles[j].parent1->label != righthand && skeleton.muscles[j].parent2->label != righthand) && skeleton.muscles[j].numvertices > 0) {
6158                                 weaponrotatemuscle = j;
6159                             }
6160                         }
6161                         weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
6162                         if (creature == wolftype)
6163                             weaponpoint = (jointPos(rightwrist) * .7 + jointPos(righthand) * .3);
6164                     }
6165                     if (weapons[i].getType() == staff) {
6166                         for (j = 0; j < skeleton.num_muscles; j++) {
6167                             if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].numvertices > 0) {
6168                                 weaponattachmuscle = j;
6169                             }
6170                         }
6171                         for (j = 0; j < skeleton.num_muscles; j++) {
6172                             if ((skeleton.muscles[j].parent1->label == rightelbow || skeleton.muscles[j].parent2->label == rightelbow) && (skeleton.muscles[j].parent1->label != rightshoulder && skeleton.muscles[j].parent2->label != rightshoulder) && skeleton.muscles[j].numvertices > 0) {
6173                                 weaponrotatemuscle = j;
6174                             }
6175                         }
6176                         //weaponpoint=jointPos(rightwrist);
6177                         weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
6178                         //weaponpoint+=skeleton.specialforward[1]*.1+(jointPos(rightwrist)-jointPos(rightelbow));
6179                         XYZ tempnormthing, vec1, vec2;
6180                         vec1 = (jointPos(rightwrist) - jointPos(rightelbow));
6181                         vec2 = (jointPos(rightwrist) - jointPos(rightshoulder));
6182                         CrossProduct(&vec1, &vec2, &tempnormthing);
6183                         Normalise(&tempnormthing);
6184                         if (animTarget != staffhitanim && animCurrent != staffhitanim && animTarget != staffgroundsmashanim && animCurrent != staffgroundsmashanim && animTarget != staffspinhitanim && animCurrent != staffspinhitanim)
6185                             weaponpoint += tempnormthing * .1 - skeleton.specialforward[1] * .3 + (jointPos(rightwrist) - jointPos(rightelbow));
6186                     }
6187                 }
6188                 if (weaponactive != k && weaponstuck != k) {
6189                     if (weapons[i].getType() == knife)
6190                         weaponpoint = jointPos(abdomen) + (jointPos(righthip) - jointPos(lefthip)) * .1 + (jointPos(rightshoulder) - jointPos(leftshoulder)) * .35;
6191                     if (weapons[i].getType() == sword)
6192                         weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
6193                     if (weapons[i].getType() == staff)
6194                         weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
6195                     for (j = 0; j < skeleton.num_muscles; j++) {
6196                         if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].numvertices > 0) {
6197                             weaponrotatemuscle = j;
6198                         }
6199                     }
6200                 }
6201                 if (weaponstuck == k) {
6202                     if (weaponstuckwhere == 0)
6203                         weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 - skeleton.forward * .8;
6204                     else
6205                         weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 + skeleton.forward * .8;
6206                     for (j = 0; j < skeleton.num_muscles; j++) {
6207                         if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].numvertices > 0) {
6208                             weaponrotatemuscle = j;
6209                         }
6210                     }
6211                 }
6212                 if (skeleton.free) {
6213                     weapons[i].position = weaponpoint * scale + coords;
6214                     weapons[i].bigrotation = 0;
6215                     weapons[i].bigtilt = 0;
6216                     weapons[i].bigtilt2 = 0;
6217                 } else {
6218                     weapons[i].position = DoRotation(DoRotation(DoRotation(weaponpoint, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords + currentoffset * (1 - target) * scale + targetoffset * target * scale;
6219                     weapons[i].bigrotation = yaw;
6220                     weapons[i].bigtilt = tilt;
6221                     weapons[i].bigtilt2 = tilt2;
6222                 }
6223                 weapons[i].rotation1 = skeleton.muscles[weaponrotatemuscle].lastrotate1;
6224                 weapons[i].rotation2 = skeleton.muscles[weaponrotatemuscle].lastrotate2;
6225                 weapons[i].rotation3 = skeleton.muscles[weaponrotatemuscle].lastrotate3;
6226                 if (weaponactive == k) {
6227                     if (weapons[i].getType() == knife) {
6228                         weapons[i].smallrotation = 180;
6229                         weapons[i].smallrotation2 = 0;
6230                         if (isCrouch() || wasCrouch()) {
6231                             weapons[i].smallrotation2 = 20;
6232                         }
6233                         if (animTarget == hurtidleanim) {
6234                             weapons[i].smallrotation2 = 50;
6235                         }
6236                         if ((animCurrent == crouchstabanim && animTarget == crouchstabanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
6237                             XYZ temppoint1, temppoint2;
6238                             float distance;
6239
6240                             temppoint1 = jointPos(righthand);
6241                             temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
6242                             distance = findDistance(&temppoint1, &temppoint2);
6243                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6244                             weapons[i].rotation2 *= 360 / 6.28;
6245                             temppoint1.y = 0;
6246                             temppoint2.y = 0;
6247                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6248                             weapons[i].rotation1 *= 360 / 6.28;
6249                             weapons[i].rotation3 = 0;
6250                             weapons[i].smallrotation = -90;
6251                             weapons[i].smallrotation2 = 0;
6252                             if (temppoint1.x > temppoint2.x)
6253                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6254                         }
6255                         if ((animCurrent == knifeslashreversalanim && animTarget == knifeslashreversalanim) || (animCurrent == knifeslashreversedanim && animTarget == knifeslashreversedanim)) {
6256                             XYZ temppoint1, temppoint2;
6257                             float distance;
6258
6259                             temppoint1 = jointPos(righthand);
6260                             temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
6261                             distance = findDistance(&temppoint1, &temppoint2);
6262                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6263                             weapons[i].rotation2 *= 360 / 6.28;
6264                             temppoint1.y = 0;
6265                             temppoint2.y = 0;
6266                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6267                             weapons[i].rotation1 *= 360 / 6.28;
6268                             weapons[i].rotation3 = 0;
6269                             weapons[i].smallrotation = 90;
6270                             weapons[i].smallrotation2 = 0;
6271                             if (temppoint1.x > temppoint2.x)
6272                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6273                         }
6274                         if (animTarget == knifethrowanim) {
6275                             weapons[i].smallrotation = 90;
6276                             //weapons[i].smallrotation2=-90;
6277                             weapons[i].smallrotation2 = 0;
6278                             weapons[i].rotation1 = 0;
6279                             weapons[i].rotation2 = 0;
6280                             weapons[i].rotation3 = 0;
6281                         }
6282                         if (animTarget == knifesneakattackanim && frameTarget < 5) {
6283                             weapons[i].smallrotation = -90;
6284                             weapons[i].rotation1 = 0;
6285                             weapons[i].rotation2 = 0;
6286                             weapons[i].rotation3 = 0;
6287                         }
6288                     }
6289                     if (weapons[i].getType() == sword) {
6290                         weapons[i].smallrotation = 0;
6291                         weapons[i].smallrotation2 = 0;
6292                         if (animTarget == knifethrowanim) {
6293                             weapons[i].smallrotation = -90;
6294                             weapons[i].smallrotation2 = 0;
6295                             weapons[i].rotation1 = 0;
6296                             weapons[i].rotation2 = 0;
6297                             weapons[i].rotation3 = 0;
6298                         }
6299                         if ((animTarget == swordgroundstabanim && animCurrent == swordgroundstabanim) || (animTarget == swordsneakattackanim && animCurrent == swordsneakattackanim) || (animTarget == swordslashparryanim && animCurrent == swordslashparryanim) || (animTarget == swordslashparriedanim && animCurrent == swordslashparriedanim) || (animTarget == swordslashreversalanim && animCurrent == swordslashreversalanim) || (animTarget == swordslashreversedanim && animCurrent == swordslashreversedanim) || (animTarget == knifeslashreversalanim && animCurrent == knifeslashreversalanim) || (animTarget == knifeslashreversedanim && animCurrent == knifeslashreversedanim) || (animTarget == swordslashanim && animCurrent == swordslashanim) || (animTarget == drawleftanim && animCurrent == drawleftanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
6300                             XYZ temppoint1, temppoint2;
6301                             float distance;
6302
6303                             temppoint1 = animation[animCurrent].position[skeleton.jointlabels[righthand]][frameCurrent] * (1 - target) + animation[animTarget].position[skeleton.jointlabels[righthand]][frameTarget] * (target); //jointPos(righthand);
6304                             temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
6305                             distance = findDistance(&temppoint1, &temppoint2);
6306                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6307                             weapons[i].rotation2 *= 360 / 6.28;
6308                             temppoint1.y = 0;
6309                             temppoint2.y = 0;
6310                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6311                             weapons[i].rotation1 *= 360 / 6.28;
6312                             weapons[i].rotation3 = 0;
6313                             weapons[i].smallrotation = 90;
6314                             weapons[i].smallrotation2 = 0;
6315                             if (temppoint1.x > temppoint2.x)
6316                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6317                         }
6318                     }
6319                     if (weapons[i].getType() == staff) {
6320                         weapons[i].smallrotation = 100;
6321                         weapons[i].smallrotation2 = 0;
6322                         if ((animTarget == staffhitanim && animCurrent == staffhitanim) || (animTarget == staffhitreversedanim && animCurrent == staffhitreversedanim) || (animTarget == staffspinhitreversedanim && animCurrent == staffspinhitreversedanim) || (animTarget == staffgroundsmashanim && animCurrent == staffgroundsmashanim) || (animTarget == staffspinhitanim && animCurrent == staffspinhitanim)) {
6323                             XYZ temppoint1, temppoint2;
6324                             float distance;
6325
6326                             temppoint1 = animation[animCurrent].position[skeleton.jointlabels[righthand]][frameCurrent] * (1 - target) + animation[animTarget].position[skeleton.jointlabels[righthand]][frameTarget] * (target); //jointPos(righthand);
6327                             temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
6328                             distance = findDistance(&temppoint1, &temppoint2);
6329                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6330                             weapons[i].rotation2 *= 360 / 6.28;
6331                             temppoint1.y = 0;
6332                             temppoint2.y = 0;
6333                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6334                             weapons[i].rotation1 *= 360 / 6.28;
6335                             weapons[i].rotation3 = 0;
6336                             weapons[i].smallrotation = 90;
6337                             weapons[i].smallrotation2 = 0;
6338                             if (temppoint1.x > temppoint2.x)
6339                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6340                         }
6341                     }
6342                 }
6343                 if (weaponactive != k && weaponstuck != k) {
6344                     if (weapons[i].getType() == knife) {
6345                         weapons[i].smallrotation = -70;
6346                         weapons[i].smallrotation2 = 10;
6347                     }
6348                     if (weapons[i].getType() == sword) {
6349                         weapons[i].smallrotation = -100;
6350                         weapons[i].smallrotation2 = -8;
6351                     }
6352                     if (weapons[i].getType() == staff) {
6353                         weapons[i].smallrotation = -100;
6354                         weapons[i].smallrotation2 = -8;
6355                     }
6356                 }
6357                 if (weaponstuck == k) {
6358                     if (weaponstuckwhere == 0)
6359                         weapons[i].smallrotation = 180;
6360                     else
6361                         weapons[i].smallrotation = 0;
6362                     weapons[i].smallrotation2 = 10;
6363                 }
6364             }
6365         }
6366     }
6367
6368     calcrot = 0;
6369     if (skeleton.free)
6370         calcrot = 1;
6371     if (animation[animTarget].attack || isRun() || animTarget == staggerbackhardanim || isFlip() || animTarget == climbanim || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim || animTarget == backhandspringanim || isWallJump())
6372         calcrot = 1;
6373     if (animCurrent != animTarget)
6374         calcrot = 1;
6375     if (skeleton.free == 2)
6376         calcrot = 0;
6377
6378     return 0;
6379 }
6380
6381
6382 /* FUNCTION?
6383  */
6384 int Person::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate, Model *model)
6385 {
6386     static int i, j;
6387     static float distance;
6388     static float olddistance;
6389     static int intersecting;
6390     static int firstintersecting;
6391     static XYZ point;
6392     static XYZ oldp1;
6393     static XYZ start, end;
6394     static float slopethreshold = -.4;
6395
6396     firstintersecting = -1;
6397
6398     oldp1 = *p1;
6399     *p1 = *p1 - *move;
6400     if (distsq(p1, &model->boundingspherecenter) > radius * radius + model->boundingsphereradius * model->boundingsphereradius)
6401         return -1;
6402     if (*rotate)
6403         *p1 = DoRotation(*p1, 0, -*rotate, 0);
6404     for (i = 0; i < 4; i++) {
6405         for (j = 0; j < model->TriangleNum; j++) {
6406             if (model->facenormals[j].y <= slopethreshold) {
6407                 intersecting = 0;
6408                 distance = abs((model->facenormals[j].x * p1->x) + (model->facenormals[j].y * p1->y) + (model->facenormals[j].z * p1->z) - ((model->facenormals[j].x * model->vertex[model->Triangles[j].vertex[0]].x) + (model->facenormals[j].y * model->vertex[model->Triangles[j].vertex[0]].y) + (model->facenormals[j].z * model->vertex[model->Triangles[j].vertex[0]].z)));
6409                 if (distance < radius) {
6410                     point = *p1 - model->facenormals[j] * distance;
6411                     if (PointInTriangle( &point, model->facenormals[j], &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]]))
6412                         intersecting = 1;
6413                     if (!intersecting)
6414                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
6415                                                                 &model->vertex[model->Triangles[j].vertex[1]],
6416                                                                 p1, &radius);
6417                     if (!intersecting)
6418                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[1]],
6419                                                                 &model->vertex[model->Triangles[j].vertex[2]],
6420                                                                 p1, &radius);
6421                     if (!intersecting)
6422                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
6423                                                                 &model->vertex[model->Triangles[j].vertex[2]],
6424                                                                 p1, &radius);
6425                     end = *p1 - point;
6426                     if (dotproduct(&model->facenormals[j], &end) > 0 && intersecting) {
6427                         start = *p1;
6428                         end = *p1;
6429                         end.y -= radius;
6430                         if (LineFacetd(&start, &end, &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]], &model->facenormals[j], &point)) {
6431                             p1->y = point.y + radius;
6432                             if ((animTarget == jumpdownanim || isFlip())) {
6433                                 if (isFlip() && (frameTarget < 5 || animation[animTarget].label[frameTarget] == 7 || animation[animTarget].label[frameTarget] == 4))
6434                                     RagDoll(0);
6435
6436                                 if (animTarget == jumpupanim) {
6437                                     jumppower = -4;
6438                                     animTarget = getIdle();
6439                                 }
6440                                 target = 0;
6441                                 frameTarget = 0;
6442                                 onterrain = 1;
6443
6444                                 if (id == 0) {
6445                                     pause_sound(whooshsound);
6446                                     OPENAL_SetVolume(channels[whooshsound], 0);
6447                                 }
6448
6449                                 if ((animTarget == jumpdownanim || isFlip()) && !wasLanding() && !wasLandhard()) {
6450                                     if (isFlip())
6451                                         jumppower = -4;
6452                                     animTarget = getLanding();
6453                                     emit_sound_at(landsound, coords, 128.);
6454
6455                                     if (id == 0) {
6456                                         envsound[numenvsounds] = coords;
6457                                         envsoundvol[numenvsounds] = 16;
6458                                         envsoundlife[numenvsounds] = .4;
6459                                         numenvsounds++;
6460                                     }
6461                                 }
6462                             }
6463                         }
6464                     }
6465                 }
6466                 if ((distance < olddistance || firstintersecting == -1) && intersecting) {
6467                     olddistance = distance;
6468                     firstintersecting = j;
6469                     *p = point;
6470                 }
6471             }
6472         }
6473         for (j = 0; j < model->TriangleNum; j++) {
6474             if (model->facenormals[j].y > slopethreshold) {
6475                 intersecting = 0;
6476                 start = *p1;
6477                 start.y -= radius / 4;
6478                 XYZ &v0 = model->vertex[model->Triangles[j].vertex[0]];
6479                 XYZ &v1 = model->vertex[model->Triangles[j].vertex[1]];
6480                 XYZ &v2 = model->vertex[model->Triangles[j].vertex[2]];
6481                 distance = abs((model->facenormals[j].x * start.x)
6482                                + (model->facenormals[j].y * start.y)
6483                                + (model->facenormals[j].z * start.z)
6484                                - ((model->facenormals[j].x * v0.x)
6485                                   + (model->facenormals[j].y * v0.y)
6486                                   + (model->facenormals[j].z * v0.z)));
6487                 if (distance < radius * .5) {
6488                     point = start - model->facenormals[j] * distance;
6489                     if (PointInTriangle( &point, model->facenormals[j], &v0, &v1, &v2))
6490                         intersecting = 1;
6491                     if (!intersecting)
6492                         intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, p1->x, p1->y, p1->z, radius / 2);
6493                     if (!intersecting)
6494                         intersecting = sphere_line_intersection(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
6495                     if (!intersecting)
6496                         intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
6497                     end = *p1 - point;
6498                     if (dotproduct(&model->facenormals[j], &end) > 0 && intersecting) {
6499                         if ((animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
6500                             start = velocity;
6501                             velocity -= DoRotation(model->facenormals[j], 0, *rotate, 0) * findLength(&velocity) * abs(normaldotproduct(velocity, DoRotation(model->facenormals[j], 0, *rotate, 0))); //(distance-radius*.5)/multiplier;
6502                             if (findLengthfast(&start) < findLengthfast(&velocity))
6503                                 velocity = start;
6504                         }
6505                         *p1 += model->facenormals[j] * (distance - radius * .5);
6506                     }
6507                 }
6508                 if ((distance < olddistance || firstintersecting == -1) && intersecting) {
6509                     olddistance = distance;
6510                     firstintersecting = j;
6511                     *p = point;
6512                 }
6513             }
6514         }
6515     }
6516     if (*rotate)
6517         *p = DoRotation(*p, 0, *rotate, 0);
6518     *p = *p + *move;
6519     if (*rotate)
6520         *p1 = DoRotation(*p1, 0, *rotate, 0);
6521     *p1 += *move;
6522     return firstintersecting;
6523 }
6524
6525 void Person::takeWeapon(int weaponId)
6526 {
6527     weaponactive = 0;
6528     weapons[weaponId].owner = id;
6529     if (num_weapons > 0) {
6530         weaponids[num_weapons] = weaponids[0];
6531     }
6532     num_weapons++;
6533     weaponids[0] = weaponId;
6534 }
6535
6536 bool Person::addClothes(const int& clothesId)
6537 {
6538     return addClothes(clothes[clothesId]);
6539 }
6540
6541 bool Person::addClothes(const char* fileName)
6542 {
6543     LOGFUNC;
6544
6545     GLubyte* array = &skeleton.skinText[0];
6546
6547     //Load Image
6548     ImageRec texture;
6549     bool opened = load_image(fileName, texture);
6550
6551     float alphanum;
6552     //Is it valid?
6553     if (opened) {
6554         if (tintr > 1) tintr = 1;
6555         if (tintg > 1) tintg = 1;
6556         if (tintb > 1) tintb = 1;
6557
6558         if (tintr < 0) tintr = 0;
6559         if (tintg < 0) tintg = 0;
6560         if (tintb < 0) tintb = 0;
6561
6562         int bytesPerPixel = texture.bpp / 8;
6563
6564         int tempnum = 0;
6565         alphanum = 255;
6566         for (int i = 0; i < (int)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
6567             if (bytesPerPixel == 3)
6568                 alphanum = 255;
6569             else if ((i + 1) % 4 == 0)
6570                 alphanum = texture.data[i];
6571             if ((i + 1) % 4 || bytesPerPixel == 3) {
6572                 if ((i % 4) == 0)
6573                     texture.data[i] *= tintr;
6574                 if ((i % 4) == 1)
6575                     texture.data[i] *= tintg;
6576                 if ((i % 4) == 2)
6577                     texture.data[i] *= tintb;
6578                 array[tempnum] = (float)array[tempnum] * (1 - alphanum / 255) + (float)texture.data[i] * (alphanum / 255);
6579                 tempnum++;
6580             }
6581         }
6582         return 1;
6583     } else {
6584         return 0;
6585     }
6586 }