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