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