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